# AI agents Source: https://docs.cyberwave.com/ai/agents Three agents: the environment assistant builds the world, the control agent drives the robots, the workflow assistant automates work. You approve every plan. Cyberwave has three agents. They sit on top of everything else: they build the environment, decide what the robots do, and write the automation, all from a plain-language request. Each one shows you what it intends to do and waits for your approval. **Builds the world.** Describe a scene; it places robots, sensors and objects, and generates assets the catalog doesn't have. **Drives the robots.** Describe a task; it plans actions and skills the twin actually supports and runs the one you approve. **Automates the work.** Describe a recurring job; it drafts or edits the workflow that does it. ## Which one do I need? | You say | Agent | Result | | ------------------------------------------------------------ | --------------------- | --------------------------------- | | "A workbench with an SO-101, a camera above it and two bins" | Environment assistant | A scene you can simulate | | "Move the Go2 to waypoint A" · "Run the pick skill" | Control agent | One approved action, executed now | | "Inspect every pallet and alert me if one is damaged" | Workflow assistant | A workflow that runs on its own | A typical session uses all three in order: build the scene, try the task with the control agent in simulation, then turn it into a workflow. ## How approval works * **Plans come first.** Every agent returns a plan or a proposal before changing anything. * **You approve one step at a time.** The control agent dispatches a single action only with explicit confirmation. The workflow assistant applies an edit only after **Review and apply**. * **Simulation before hardware.** Plan and test in simulation, then plan again for the real robot. * **A person can always take over** from the twin's controller panel. See [Ways to control a robot](/ai/control). ## Where you use them | | Environment assistant | Control agent | Workflow assistant | | -------------- | ---------------------------------------- | ------------------------------------------------------ | ------------------------------------------------ | | **Dashboard** | Environment editor → **Agent** | Simulate → **Agent** | Workflow workbench → **Prompt** or **Assistant** | | **Python SDK** | `cw.agents.environment` | `cw.agents.control` | `cw.agents.workflow` | | **MCP** | `cw_plan_scene`, `cw_create_environment` | `cw_plan_control_action`, `cw_dispatch_control_action` | `cw_create_workflow_from_prompt` | To give Claude Code, Cursor or any MCP client these abilities, see the [MCP server](/overview/tools/mcp-server) and the [Claude skill](/overview/tools/claude-skill) under Reference. ## Next steps The most common starting point: plan, approve and run an action. Voice in, a plan out, the arm moves. # Ways to control a robot Source: https://docs.cyberwave.com/ai/control Five ways to control your robots: manual input, skills, workflows, VLA models and RL policies. What decides each action, and when to use which. Cyberwave gives you five ways to control the robots in an environment. They are alternatives, not steps: pick the one that fits the task, and switch whenever you like. Each drives the same twins, in simulation or on hardware, and exactly one **controller** drives a given twin at any moment. Switching between them doesn't stop telemetry or recording, so a session can start manual, hand over to a model, and fall back to a person if something goes wrong. ```mermaid theme={null} flowchart LR M[Manual input
keyboard · gamepad · leader arm] --> E S[Skills
named actions] --> E W[Workflows
automation] --> E V[VLA models
learned from demonstrations] --> E R[RL policies
learned in simulation] --> E E[Robots in your environment
one controller per twin at a time] ``` | Way to control | Who decides the next action | Use it for | Start here | | ---------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------- | | **Manual input** | A person, with keyboard, gamepad or a leader arm | Demos, recovery, recording demonstrations | [Teleoperation](/feature-reference/environment-editor/teleoperation) | | **Skills** | A named action the robot already knows: a saved pose, a standard command, a trained skill | "Go home", "open gripper", "pick", called by a person, a workflow or an agent | [Standard arm commands](/feature-reference/arm-commands) | | **Workflows** | Rules you draw: trigger → model → decision → command | Repeatable automation, alerts, inspections | [Workflows](/feature-reference/workflows) | | **VLA models** | A vision-language-action model, from camera frames and an instruction | Manipulation learned from demonstrations | [Fine-tune SmolVLA](/feature-reference/ml-models/smolvla-training) | | **RL policies** | A policy trained by reward in simulation | Locomotion and dynamic control | [RL tasks](/feature-reference/rl-tasks) | ## Assign a controller * **In the dashboard:** select the twin and use **Assign Controller**. A person can take over from the same panel at any time. * **From Python:** `twin.policy.list()` shows the controllers available to a twin, `twin.policy.assign(policy)` hands it over, and `twin.policy.ensure_attached()` lets your script drive it. * **From an agent:** the [control agent](/ai/control-agent) plans an action or a skill run, and you approve it before it executes. How controllers are routed, where each type runs, and how code controllers and RL checkpoints run on a controller host: [Controllers and handover](/feature-reference/online-controllers). ## Where the models come from Manual sessions, skills and workflows all produce recordings. Recordings become datasets, and datasets train VLA models and RL policies. See [Data for training](/feature-reference/datasets/import). ## Next steps A camera, a model and an SO-101 twin that picks and sorts. Record demonstrations, fine-tune, deploy the model as the controller. Triggers, models and robot commands on a canvas. Let an assistant plan the action, then approve it. # Control agent Source: https://docs.cyberwave.com/ai/control-agent Tell a robot what to do in plain language. The control agent plans actions the twin actually supports, and runs one only after you approve it. The **control agent** turns a request like *"move the Go2 to waypoint A"* or *"run the pick skill on the SO-101"* into concrete actions. It only proposes actions the twin can actually perform: each twin exposes **control surfaces**, derived from its metadata, that list the controls it supports. Nothing moves until a person approves one action. **Use it from:** * **The dashboard:** in **Simulate → Agent**, describe the task and any limit, then select **Plan**. Check the robot, controller and limits before you execute. Cancelling stops only that run. * **Python:** `cw.agents.control`, shown step by step below. * **Your own AI tools:** the MCP server exposes the same calls to Claude Code, Cursor and any MCP client (see [below](#from-your-ai-tools-mcp)). The agent plans in the cloud. The action runs wherever the twin runs: in simulation, or on the real robot through its edge device. ```mermaid theme={null} sequenceDiagram participant You as Your code participant CW as Control agent participant T as Twin (sim or real) You->>CW: surfaces(env) — what can each twin do? You->>CW: plan(env, "instruction", twin) CW-->>You: summary, warnings, dispatchable_actions Note over You: a human reviews the plan You->>CW: dispatch(env, one action, confirmed=True) CW->>T: execute You->>CW: actions.wait(action_id) CW-->>You: completed / failed / cancelled / blocked ``` ## The four calls | Step | Call | Returns | | -------- | -------------------------------------------------------------------- | ------------------------------------------------- | | Inspect | `cw.agents.control.surfaces(env_uuid, mode=...)` | One entry per twin with its `controls` | | Plan | `cw.agents.control.plan(env_uuid, message, twin_uuid=..., mode=...)` | A plan dict. Nothing is executed. | | Dispatch | `cw.control.dispatch(env_uuid, action, confirmed=True, mode=...)` | The dispatch result, with an `action_id` to track | | Wait | `cw.actions.wait(action_id, twin_uuid=..., timeout=...)` | The final status dict | `cw.control` is an alias for `cw.agents.control`. All four calls wrap REST endpoints. Failures raise `CyberwaveAPIError` with a `Failed to ...` prefix. ## Walk through it Every call takes the environment UUID. Get it from a twin you already have: ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() robot = cw.twins.get("acme/twins/go2-yard") # your twin's slug or UUID env_uuid = str(robot.environment_id) twin_uuid = str(robot.uuid) ``` ```python theme={null} for surface in cw.agents.control.surfaces(env_uuid, mode="simulation"): available = [c.get("label") or c.get("kind") for c in surface.get("controls", []) if c.get("available")] print(surface.get("twin_name"), surface.get("twin_uuid"), available) ``` Surfaces are derived from each twin's metadata. If a twin shows no available controls, the agent has nothing to plan with. Fix the twin's controller setup first. When you omit `mode`, surfaces are evaluated as `live`. ```python theme={null} plan = cw.agents.control.plan( env_uuid, "Move the Go2 to waypoint A", twin_uuid=twin_uuid, mode="simulation", ) print(plan.get("summary")) print("readiness:", plan.get("readiness")) print("requires confirmation:", plan.get("requires_confirmation")) for warning in plan.get("warnings", []): print("warning:", warning) for missing in plan.get("missing_requirements", []): print("missing:", missing) ``` `plan()` never executes anything. Read `warnings` and `missing_requirements` before you go on. `dispatchable_actions` holds the actions you can send. Each one is a dict with a `kind`, a `target_twin_uuid` and a `payload`. ```python theme={null} actions = plan.get("dispatchable_actions") or [] if not actions: raise SystemExit("Nothing to dispatch. Check missing_requirements.") action = actions[0] print(action) if input("Dispatch this action? [y/N] ").strip().lower() != "y": raise SystemExit("Not dispatched.") ``` ```python theme={null} result = cw.control.dispatch(env_uuid, action, confirmed=True, mode="simulation") if result.get("action_id"): final = cw.actions.wait(result["action_id"], twin_uuid=twin_uuid, timeout=60) print(final.get("status"), final.get("message")) ``` Dispatch **one** action at a time. Check its result, and the twin's measured state, before you send the next one. `wait()` needs the twin UUID because the status endpoint is scoped to the twin. ## Modes Pass the same `mode` to `surfaces`, `plan` and `dispatch`. A plan made for simulation is not a plan for hardware: plan again when you switch. | Mode | Targets | Default for | | -------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- | | `"preview"` | The lightweight kinematic runtime. The SDK maps `playground` to this mode. | `cw.agents.workflow.plan(...)`, `preview(...)` | | `"simulation"` | The environment's simulation. Pass `simulation_backend=` to pick the backend. | `plan(...)`, `dispatch(...)`, `resolve_route(...)` | | `"live"` | The real robot, through its paired edge device | `surfaces(...)` when `mode` is omitted | A MuJoCo simulation is a billable cloud instance, about 0.6 credits per hour. Start one with `sim = cw.environments.simulations.start(env_uuid, backend="mujoco", duration=300)` and call `sim.stop()` when you are done. See [credits](/billing/credits). ## Safety rules Planning never authorizes motion. `confirmed` defaults to `False` on `dispatch()`. Set it to `True` only after a person (or a check you trust) has approved that specific action. * **One bounded action per dispatch.** One pose, one joint target, one navigation goal, or one stop. * **Simulation first.** Run the same instruction in simulation, check the result, then plan again in `live`. * **Before a live dispatch**, make sure that: the request really is for physical execution, exactly one physical twin is targeted, the twin's edge device and telemetry are current, and a stop is available. * **Don't retry blindly.** If `dispatch()` or `wait()` times out or returns an unclear status, don't resend the motion. Read the twin's state, send a stop if it is safe, and ask the operator. * **Keep a human controller one click away.** See [safety and takeover](/feature-reference/environment-editor/teleoperation). `cw.actions.wait()` returns when the action reaches `completed`, `failed`, `cancelled` or `blocked`. With the default `raise_on_failure=True`, any status other than `completed` raises `RuntimeError`. If no terminal status arrives within `timeout` seconds, it raises `TimeoutError`. A single failed status poll does not end the wait. ## Choosing the model and the controller `plan()` accepts optional arguments to steer the agent: | Argument | Use | | ----------------------------------- | ---------------------------------------------------------------------------------- | | `llm_model_uuid` / `llm_model_name` | Pick the LLM that writes the plan | | `mlmodel_uuid` | Pick a model record from your catalog for the agent | | `controller_policy_uuid` | Plan a run of a specific controller policy, for example a trained VLA or RL policy | | `simulation_backend` | Choose the simulation backend in `simulation` mode | ## Skip the LLM: resolve a route directly When you already know which control you want, skip the language step. `options()` lists the environment's control routes and action specs. `resolve_route()` turns one route and its inputs into a plan, without executing it. Dispatch its `dispatchable_actions` exactly as above. ```python theme={null} options = cw.control.options(env_uuid) print(options) # control routes, action specs and helper options # route_id and route_inputs come from the options above plan = cw.control.resolve_route( env_uuid, route_id, twin_uuid, route_inputs, mode="simulation" ) ``` If the resolved plan reports missing setup, fill in only the fields it asks for, then resolve again. ## Automate it instead For standing behavior, such as *"inspect every pallet and alert me if one is damaged"*, use the [workflow assistant](/ai/workflow-assistant). It drafts a workflow that runs on its own instead of a single action. ## From your AI tools (MCP) The same flow is available to Claude Code, Cursor and any MCP client, with no code: | SDK | MCP tool | | ---------------------------- | ---------------------------- | | `cw.agents.control.surfaces` | `cw_list_control_surfaces` | | `cw.agents.control.plan` | `cw_plan_control_action` | | `cw.control.resolve_route` | `cw_resolve_control_route` | | `cw.control.dispatch` | `cw_dispatch_control_action` | `cw_plan_control_action` only plans. The assistant must call `cw_dispatch_control_action` with one explicit action. If the environment's control-plane access is set to workflows only, the MCP server refuses direct dispatch with `CONTROL_PLANE_POLICY_DENIED`. The [Claude skill](/overview/tools/claude-skill) applies the safety rules above before any live dispatch. Set it up with the [MCP server](/overview/tools/mcp-server) guide. **Want your own LLM in the loop instead?** The [natural-language SO-101 agent](/tutorials/so101-natural-language-agent) calls Claude directly with a camera frame, gets a JSON motion plan, and runs it with the SDK. ## Common errors | Message | Cause | Fix | | ----------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------- | | `ValueError: environment_uuid is required` | Empty environment ID | Pass `str(twin.environment_id)` | | `ValueError: message is required` | Blank instruction | Pass a non-empty instruction | | `ValueError: twin_uuid is required by the action status endpoint` | `actions.wait()` without `twin_uuid` | Pass the twin the action targets | | `CyberwaveAPIError: Failed to plan control action: ...` | The planning request failed | Read the wrapped message. For auth and workspace errors, see [Troubleshooting](/support/troubleshooting). | | `CyberwaveAPIError: Failed to dispatch control action: ...` | The backend rejected the action | Plan again. Don't edit and resend an old action. | ## Next steps The environment assistant, the control agent and the workflow assistant. Where the agent fits next to manual input, skills, workflows and learned policies. Turn a recurring task into a workflow from one sentence. Give Claude Code or Cursor the same planning and dispatch tools. # Environment assistant Source: https://docs.cyberwave.com/ai/environment-assistant Describe a scene in plain language and the environment assistant builds it: robots, sensors, objects and, when the catalog has none, new assets. The **environment assistant** builds and edits the world your robots live in. You describe the scene, for example *"a workbench with an SO-101, a camera above it and two bins"*, and it finds the right twins in the catalog, places them and proposes the changes for you to accept. When nothing in the catalog fits, it can generate a new asset. ## What it does | You ask for | The assistant | | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A scene or a change to it | Searches the catalog first, places twins, and uses simple procedural primitives for basic geometry | | An object the catalog doesn't have | Generates a **private URDF asset** in the background while you keep editing ([Generate assets](/feature-reference/environment-editor/assistant-asset-generation)) | | A change to a generated asset | Builds a new candidate revision; the current asset stays unchanged until you accept the preview | | Help with a reference | Takes tagged scene objects and reference images alongside your message | Generated assets start private and scoped to the environment that asked for them. Sharing them further follows the normal asset visibility controls. ## Use it in the editor 1. Open an environment and select **Agent** in the right-hand panel. 2. Describe what you want. Tag scene objects or attach a reference image if it helps. 3. Review what the assistant proposes, then accept it. The conversation stays the same when you switch between **Edit** and **Monitor** in Simulate or Live, within the same page session. Unsent drafts, tagged objects and reference images are kept when you visit **Control** and come back. In **Monitor**, action cards are read-only, and switching to Monitor asks the assistant to stop unfinished edits without stopping running robots or training jobs. To act on the robots themselves, use the [control agent](/ai/control-agent); it has its own composer. More on the editor: [Environment editor](/feature-reference/environment-editor). ## Use it from Python ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() # Create a new environment from a description env = cw.agents.environment.create("A workbench with an SO-101 arm, a camera above it and two bins") # Continue the conversation in an existing environment reply = cw.agents.environment.message(environment_uuid, "Add a second camera on the left side") # Models that can run the assistant print(cw.agents.environment.models()) ``` `message()` also accepts the conversation `history`, a `pending_confirmation` to answer, and an image (`image_base64`, `image_mime_type`) as a reference. ## From your AI tools (MCP) With the [MCP server](/overview/tools/mcp-server), Claude Code, Cursor or any MCP client can plan a scene with `cw_plan_scene` and create environments with `cw_create_environment`. `cw_plan_scene` is advisory: it returns a plan and checks, and changes nothing. ## Next steps Once the scene is ready, tell the robots what to do. Build stages, revisions and limits for generated URDF assets. # AI models Source: https://docs.cyberwave.com/ai/models What an AI model is on Cyberwave: the task it performs, the modalities it takes and returns, and its role: perceiving, reasoning, or controlling a robot. An **AI model** on Cyberwave is a catalog entry that says four things: what it takes in (**modalities**), what job it does (**task**), what it returns, and **where it runs**. Once a model is in the catalog, the Playground, workflows, the Python SDK and edge workers all use it the same way. ## Three roles a model can play **Sensor data in, facts out.** Detection, segmentation, pose, depth, captioning, speech-to-text. Something else (your code, a workflow, an agent) decides what the robot does with the result. **Instructions in, plans out.** Language and vision-language models answer prompts and break a goal into steps. They also power the [AI agents](/ai/agents). **Observations in, robot actions out.** VLA models and RL policies produce joint or velocity commands directly, so they run as the robot's [controller](/ai/control). The same camera can feed all three: a detector finds the cup, a language model decides which bin it belongs in, and a VLA policy picks it up. ## Modalities: what goes in, what comes out Each model declares the inputs it accepts. The catalog filters on them. | Input | Catalog capability | Typical use | | ------------- | -------------------------- | ----------------------------- | | Images | `can_take_image_as_input` | Inspection, detection | | Video | `can_take_video_as_input` | Monitoring, teleoperation | | Audio | `can_take_audio_as_input` | Voice commands, sound events | | Text | `can_take_text_as_input` | Prompts, instructions | | Robot actions | `can_take_action_as_input` | Behavior cloning, RL policies | Outputs come back as typed results in the SDK: detections (boxes, masks, keypoints, oriented boxes), classifications, depth maps, semantic masks, embeddings, text, JSON and images. ## Tasks: the job you ask a model to do A **task** fixes the prompt and the shape of the answer, so every model that supports it returns the same format. Models that support several tasks let you pick one in the Playground and in the workflow **Call Model** node. | Task | What you get back | | ------------------------------ | ------------------------------------------------ | | Free prompt | The model's text, passed through unchanged | | Caption | One sentence describing the image | | Detect points | A point per object, for "where is X?" | | Detect bounding boxes | A box per object | | Segment | A mask per object | | Predict image-plane trajectory | Ordered 2D waypoints | | Plan steps | A goal broken into ordered sub-tasks | | Detect objects in 3D | Label, pose and size in the camera frame | | Predict grasps | Ranked parallel-jaw grasps | | Detect spatial relations | A scene graph of subject–relation–object triples | Output schemas and parsing: [Tasks and outputs](/feature-reference/ml-models/structured-actions). ## Where models come from and where they run * **The catalog:** public models plus your workspace's own, filterable by input, task, vendor, size and edge runtime. See the [model catalog](/feature-reference/ml-models). * **Providers:** local or edge runtimes, cloud APIs such as OpenAI and Anthropic, Hugging Face, or your own inference server. * **Your own model:** register one behind your API, or upload code for Cyberwave to host. See [Bring your own model](/feature-reference/ml-models/uploading-your-model). | Runs on | Good for | How | | --------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | **Edge** | Low latency, privacy, frames never leave the site | [Edge workers](/feature-reference/workflows/workers/overview), with runtimes such as Ultralytics, ONNX Runtime, TensorRT, TFLite, Hailo and Whisper | | **Cloud** | Large models, VLMs, LLMs, VLA inference | [Playground](/feature-reference/ml-models/playground), workflows, [cloud nodes](/overview/tools/vla-cloud-node) | ## Use a model Run any catalog model on an image, a frame or a recording, no code. The Call Model node, with the same tasks as the Playground. `cw.models.load("yolo26n.pt").predict(frame)`, locally or in the cloud. VLA models and RL policies drive the robot directly. # Connect AI to robots Source: https://docs.cyberwave.com/ai/overview How AI models see through a robot's sensors, decide what it does, help you build and automate, and get better from every run. Cyberwave sits between AI models and physical machines. AI agents sit on top: they build the environment, plan the actions and write the workflows. Below them, models perceive through a twin's sensors, a controller turns decisions into motion, and every run becomes data for the next model. The twin is the same object whether the robot is simulated or real, so what you test in simulation runs on hardware without code changes. ```mermaid theme={null} flowchart TB A[AI agents
build · control · automate] A --> P[AI models
perceive · reason · act] A --> C[Control
manual · skills · workflows · VLA · RL] S[Sensors] --> P P --> C C --> T[Digital twin] T <-->|same API| R[Robot, sim or real] T --> L[Learn
recordings → datasets] L --> C ``` ## The four parts Assistants that build the environment, control the robot and write workflows from a plain-language request. You approve every plan. Models that perceive (*a cup at x = 212 px*, *"stop"*), reason (plan steps from a goal) or act (VLA and RL policies that drive the robot). Any task, any modality, on the edge or in the cloud. Choose who drives the robot, from a person with a gamepad to a policy that learned the task: manual input, skills, workflows, VLA models, RL policies. Every run can be recorded. Recordings become datasets, datasets train the next VLA or RL policy, and the policy deploys back to the same twin. ## Where to start | You want to | Start with | Needs | | --------------------------------------------- | -------------------------------------------------------------- | ----------------- | | See a model drive a robot, end to end | [Your first AI loop: see, pick, sort](/overview/first-ai-loop) | Laptop webcam | | Automate a task without code | [Workflows](/feature-reference/workflows) | Browser | | Tell a robot what to do in plain language | [Control agent](/ai/control-agent) | Python or browser | | Teach a manipulation task from demonstrations | [Train a VLA on the SO-101](/tutorials/train-vla-cyberwave) | SO-101 arm | | Train a policy in simulation | [Train an RL policy](/tutorials/train-rl-policy) | Browser | ## Where it runs | | Browser (Playground) | Cloud | Edge (Pi, Jetson, x86) | | --------------- | -------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- | | **Good for** | Trying things, demos, kinematic checks | Heavy models, planning, VLA inference, MuJoCo, training | Low latency, privacy, poor connectivity | | **Cost** | Free | Credits ([billing](/billing/credits)) | Your hardware | | **Switch with** | `cw.affect("playground")` | `cw.affect("simulation")`, cloud nodes | `cyberwave pair`, [edge workers](/feature-reference/workflows/workers/overview) | Models can move real hardware. Keep a person one click away from taking control, approve agent plans before they run, and test in simulation first. ## Next steps The five kinds of controller and when to use each. One twin model for arms, quadrupeds, drones and cameras. # Workflow assistant Source: https://docs.cyberwave.com/ai/workflow-assistant Describe a recurring task and the workflow assistant drafts or edits the workflow: triggers, models, conditions and robot commands. You review every change. The **workflow assistant** turns a recurring task into automation. You describe the behavior, for example *"inspect every pallet and alert me if one is damaged"*, and it drafts a [workflow](/feature-reference/workflows): the trigger, the models, the decisions and the robot commands. It can also change an existing workflow node by node. Every change is shown as a proposal before it is applied, and applying a draft doesn't activate the workflow. Use it when the job should keep running on its own. For a one-off action ("move to waypoint A now"), use the [control agent](/ai/control-agent) instead. ## Use it in the workbench * **Create or edit a workflow:** select the workflow in the workbench, then use **Prompt** or the right-hand **Assistant** tab. Click the assistant's title to switch between the **Environment assistant** and the **Workflow assistant**. The workflow option needs the workbench open. * **Configure one node with AI:** in an editable environment workflow, **Configure with AI** opens the workflow assistant for the selected node. Edit the request, choose **Plan edit**, review the proposal, then **Review and apply**. ## Use it from Python The workflow assistant works in steps, so you can inspect each one before anything changes: | Step | Call | Changes anything? | | ------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Preview the strategy | `cw.agents.workflow.preview(env_uuid, prompt)` | No | | Plan the workflow | `cw.agents.workflow.plan(env_uuid, prompt)` | No | | Set up and draft | `cw.agents.workflow.setup_and_draft(env_uuid, prompt, confirmed_actions=[...])` | Yes: applies the setup actions you confirmed and drafts the workflow (private by default) | | Edit an existing workflow | `cw.agents.workflow.apply_plan(env_uuid, workflow_uuid, prompt)` | Yes: a constrained edit to that workflow | ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() prompt = "Inspect every pallet and alert me if one is damaged" plan = cw.agents.workflow.plan(env_uuid, prompt) # read-only print(plan) # review it first draft = cw.agents.workflow.setup_and_draft(env_uuid, prompt, agent_plan=plan) ``` Then open the draft in the workbench, test it against simulation, and activate it when you are happy. See [Run a workflow against simulation](/feature-reference/workflows/simulation-execution-target). ## From your AI tools (MCP) With the [MCP server](/overview/tools/mcp-server), Claude Code, Cursor or any MCP client can use `cw_create_workflow_from_prompt` to preview or draft a workflow, then `cw_list_workflows`, `cw_get_workflow` and `cw_trigger_workflow` to find and run it. ## Next steps Triggers, nodes, execution and monitoring. Every node the assistant can use. # A2A partner task API Source: https://docs.cyberwave.com/api-reference/a2a-partner-api Submit a natural-language store-operations task and stream live status over the A2A protocol. Partners submit a task in plain text and follow it to completion over a live SSE stream, using the open [A2A protocol](https://a2a-protocol.org) instead of a one-off integration. ## Discovery `GET /.well-known/agent-card.json` — public, no auth. Declares the endpoint URL and the bearer auth scheme a client should use. ## Authentication Authenticate using a [Cyberwave API Token](/api-reference/overview#authentication) from your [profile page](https://cyberwave.com/profile). The token must belong to the target workspace and include the `a2a` scope key. Send it on every request: ```http theme={null} Authorization: Bearer ``` Use a workspace-scoped API token for the full task lifecycle. User session tokens are not supported for starting tasks. ## Endpoint `POST /api/v1/a2a` — single JSON-RPC 2.0 endpoint (`{jsonrpc, id, method, params}`). Auth: `Authorization: Bearer `, a workspace-scoped partner token (not a user session token). `params.metadata.storeId` selects the target Environment by the last segment of its slug: for `acme/envs/aisle-a3`, send `aisle-a3`. The Environment must belong to the token's workspace. | Method (current) | Alias accepted | Description | | ---------------------- | ------------------- | ---------------------------------------- | | `SendStreamingMessage` | `message/stream` | Start a task, opens an SSE stream | | `SubscribeToTask` | `tasks/resubscribe` | Reattach to an in-progress task's stream | | `GetTask` | `tasks/get` | Poll current task state | | `CancelTask` | `tasks/cancel` | Cancel an in-progress task | `SendMessage` (non-streaming) and `GetExtendedAgentCard` are recognized but return `UnsupportedOperationError` — not implemented yet. ## Start a task and receive updates ```bash theme={null} curl -N -X POST "https://api.cyberwave.com/api/v1/a2a" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "message/stream", "params": { "message": { "role": "user", "messageId": "req-001", "parts": [{ "kind": "text", "text": "Check aisle 3 for missing stock, refill it, then verify" }] }, "metadata": { "storeId": "aisle-a3" } } }' ``` The response to this POST **is the update stream**; there is no separate GET stream URL to open. `curl -N` disables output buffering so events appear as they arrive. Keep the connection open until you receive `finished`. A successful streaming response has `Content-Type: text/event-stream`. Planning and initial dispatch happen before streaming begins, so the first event may take time to arrive. Check both the HTTP status and response content type: a rejected request can return JSON instead of SSE, including a JSON-RPC `error` with HTTP 200. ### Event format Each SSE frame contains an `event:` name and a `data:` line containing JSON, followed by a blank line. The JSON has its own `type` field; task payloads are nested inside `data`. These are Cyberwave's current event envelopes. Streaming frames do not wrap their payload in a JSON-RPC `result` object. Parse the shapes below when integrating a client, even if your A2A library expects standard status or artifact update envelopes. | Event | Payload | Client action | | ---------- | ---------------------------------------------------------- | ------------------------------------------------------------ | | `task` | `data.id`, `data.status`, `data.metadata` | Save the task ID for polling, cancellation, and reconnects. | | `update` | `data.taskId`, `data.state`, `data.reasoning` | Replace the displayed progress with this full snapshot. | | `finished` | `data.taskId`, `data.state`, `data.summary`, `data.videos` | Record the terminal outcome and stop consuming. | | `final` | `payload.partner_task_uuid`, `payload.final_state` | Ignore this transport completion event after `finished`. | | `error` | Top-level `message` and error details such as `status` | Handle a streaming error and check the task using `GetTask`. | For example, a successful task could emit the following frames. The identifiers, robot name, and summary are illustrative: ```text theme={null} event: task data: {"type":"task","data":{"id":"task_12345678123456789abc123456789abc","status":{"state":"TASK_STATE_WORKING"},"metadata":{"name":"Check aisle 3","robots":[{"robotId":"87654321-4321-6789-abcd-123456789abc","name":"Aisle robot"}]}}} event: update data: {"type":"update","data":{"kind":"update","taskId":"task_12345678123456789abc123456789abc","state":"TASK_STATE_WORKING","reasoning":{"central":[],"robots":[{"robotId":"87654321-4321-6789-abcd-123456789abc","name":"Aisle robot","role":"navigating","status":"running","steps":[]}]}}} event: finished data: {"type":"finished","data":{"kind":"finished","taskId":"task_12345678123456789abc123456789abc","state":"TASK_STATE_COMPLETED","summary":"Aisle check completed.","videos":[]}} event: final data: {"type":"final","payload":{"partner_task_uuid":"12345678-1234-5678-9abc-123456789abc","final_state":"completed"}} ``` The first `task` event contains the current state, which may already be terminal for a fast task or a retried request. Do not require an `update` before accepting `finished`. Treat `finished` as the authoritative end of the task; `final` is only transport bookkeeping and uses the internal lowercase state spelling. ### Progress fields and task states An `update` is a full current snapshot, not a text delta or a token stream: * `reasoning.central` contains task-level progress entries. * `reasoning.robots` lists robot assignments with `robotId`, `name`, `role`, `status`, and `steps`. * Robot `status` values are lowercase: `queued`, `running`, `completed`, `failed`, `cancelled`, or `blocked`. These differ from the task-level state values below. The current implementation leaves `central` and `steps` empty; clients should show task and robot status even when there is no explanatory text. `videos` is also currently an empty list; video results are not populated by this API. | Task state | Meaning | | --------------------------- | -------------------------------------------------------------- | | `TASK_STATE_SUBMITTED` | Task accepted. | | `TASK_STATE_WORKING` | Task is in progress. | | `TASK_STATE_COMPLETED` | Task completed successfully; terminal. | | `TASK_STATE_FAILED` | Task failed; terminal. | | `TASK_STATE_CANCELED` | Task canceled; terminal. | | `TASK_STATE_REJECTED` | Task rejected; terminal. | | `TASK_STATE_INPUT_REQUIRED` | Reserved for additional input; not currently produced. | | `TASK_STATE_AUTH_REQUIRED` | Reserved for additional authorization; not currently produced. | A `finished` event can report any terminal outcome, so check `data.state` before marking a task successful. ### Stream lifetime and client handling Progress is checked approximately once a second, and updates are emitted only when task state, robot status, or progress-entry counts change. This is a status stream, not a continuous telemetry feed. Ignore SSE comment lines such as `: keep-alive`; they are not task events. The current stream loop has a 30-minute limit. If the task is still nonterminal at that limit, it is marked failed, in-flight assignments are canceled, and `finished` reports `TASK_STATE_FAILED` with a timeout summary. Use an HTTP client that supports a streaming POST with an Authorization header. The browser's native `EventSource` interface does not support this request shape. When implementing a reader: 1. Buffer incoming bytes until complete SSE frames are available; network chunks do not necessarily align with frames. 2. Parse the JSON from each frame's `data:` field and dispatch on `type`. 3. Save `data.id` from `task` and update progress from subsequent `update` events. 4. On `finished`, store the state and summary and close the reader. 5. If the stream errors or closes before `finished`, check the task and reconnect as described below. A disconnected stream does not mean the task completed or was canceled. ## Environment control policy The selected Environment controls which execution routes A2A may use: | Environment setting | A2A behavior | | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Direct twin control only | Plans and dispatches commands to eligible twins. | | Workflows only | Matches the request against the Environment's active manual workflows, using each workflow's name and description, and triggers the best match. Direct commands are rejected. | | Direct twin control and workflows | Chooses between a matching workflow and direct twin control for each request. | Every Environment, new or existing, defaults to **Direct twin control and workflows** so upgrading never blocks a routine that worked before. Environment authors configure this under **Environment settings → Advanced → Control plane access**. Choosing **Direct twin control only** disables workflow execution everywhere for that Environment, not only for A2A — the same manual trigger used by the web app's Run button and the SDK is gated too. In workflows-only mode, nodes inside an allowed workflow may still command twins; the restriction applies to the external A2A request, not to the workflow's authored behavior. Only active, non-deleted workflows attached to the selected Environment, visible to the caller, and containing an enabled manual trigger are candidates. If no permitted route matches the request, the task finishes in the `rejected` state without dispatching a twin command. When A2A starts a workflow, the task's `metadata.workflow` object identifies the selected workflow and execution: ```json theme={null} { "workflow": { "uuid": "workflow-uuid", "name": "Restock aisle", "description": "Restock an aisle and verify shelf inventory.", "execution_uuid": "execution-uuid" } } ``` The A2A task remains `working` while the workflow runs and mirrors its terminal state: workflow success becomes `completed`, an execution error becomes `failed`, and cancellation becomes `canceled`. ## Reconnect to an existing task Once you have a task ID, POST `SubscribeToTask` (or `tasks/resubscribe`) to the same endpoint with `params.id`. Use an API token from the same workspace: ```bash theme={null} curl -N -X POST "https://api.cyberwave.com/api/v1/a2a" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{ "jsonrpc": "2.0", "id": "2", "method": "tasks/resubscribe", "params": { "id": "task_12345678123456789abc123456789abc" } }' ``` Replace the example ID with the `data.id` from your initial `task` event. The top-level JSON-RPC `id` identifies this request; `params.id` identifies the task. The reattached stream starts immediately with an `update` containing the current snapshot, **not** another `task` event. It then emits changed snapshots and a terminal `finished` event using the same shapes as the original stream. Resubscription does not replay missed events. There are no SSE event IDs or `Last-Event-ID` replay support. If the task is already terminal, `SubscribeToTask` returns `-32004` (`UnsupportedOperationError`) as JSON; use `GetTask` to read its state. A task can finish between polling and reconnecting, so handle this error even after a nonterminal poll result. If the original connection closed before you received a task ID, retry `message/stream` with the original `message.messageId` and request payload to recover the existing task without dispatching it again. ## Poll or cancel a task `GetTask` (`tasks/get`) returns a normal JSON response rather than a stream: ```bash theme={null} curl -X POST "https://api.cyberwave.com/api/v1/a2a" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "3", "method": "tasks/get", "params": { "id": "task_12345678123456789abc123456789abc" } }' ``` Its `result` has the same task envelope as the initial stream event: ```json theme={null} { "jsonrpc": "2.0", "id": "3", "result": { "id": "task_12345678123456789abc123456789abc", "status": { "state": "TASK_STATE_COMPLETED" }, "metadata": { "name": "Check aisle 3", "robots": [ { "robotId": "87654321-4321-6789-abcd-123456789abc", "name": "Aisle robot" } ] } } } ``` `GetTask` returns task state and robot identities; it does not return the `update` reasoning snapshot or the `finished` summary and videos. Persist the `finished` payload if your integration needs those results later. To cancel, send the same request with `method: "tasks/cancel"` (alias `CancelTask`). It returns a task envelope with `TASK_STATE_CANCELED`; an attached stream reports the terminal outcome through `finished`. Canceling an already terminal task returns `-32002` (`TaskNotCancelableError`). Closing your client connection is not a cancellation request. ## Error handling Standard JSON-RPC (`-32700` parse error, `-32600` invalid request, `-32601` method not found, `-32602` invalid params, `-32603` internal error), plus `-32001` (task not found), `-32002` (task not cancelable), `-32004` (unsupported operation). JSON-RPC errors normally return HTTP 200 with an `error` object instead of a stream. For example, reconnecting after completion returns: ```json theme={null} { "jsonrpc": "2.0", "id": "2", "error": { "code": -32004, "message": "UnsupportedOperationError: task already in a terminal state" } } ``` Missing or invalid authentication returns HTTP 401. A token without the `a2a` scope returns HTTP 403. Check these HTTP failures as well as JSON-RPC errors. An `error` event after the SSE response has started is a transport error, not a `finished` task outcome; poll the task to determine its state. ## Retries and idempotency Always send `message.messageId`, using a unique value for each new logical task. If a request is retried with the **same** `messageId` (e.g. after a dropped SSE connection before a `finished` event arrived), the API returns the original task instead of dispatching the same robots again. Deduplication is scoped to the workspace, so keep the same ID for retries of one logical request and use a new ID for each new task. A **different** `messageId` is always treated as a new task, even if the text is identical to a previous request. `messageId` is optional for backward compatibility, but a request that omits it gets no idempotency protection at all: every such call starts a new task and dispatches robots again, even if it is an exact retry of the previous one. Partners should always set `messageId`. # ROS 2 driver Source: https://docs.cyberwave.com/api-reference/autonomous-navigation-driver Docker images, configuration, and ROS 2 topic reference for the Go2 navigation driver. ## Docker Images The full robot stack is published as four images on Docker Hub, each available in three tags (`jazzy`, `humble`, `jetson-humble`): | Image | Description | | ------------------------------------ | ------------------------------------------------------------- | | `cyberwaveos/go2-ros2-driver` | Go2 driver, streaming bridges, edge bridge | | `cyberwaveos/ros2-nav2` | Nav2 navigation stack (robot-agnostic) | | `cyberwaveos/ros2-slam` | SLAM — RTAB-Map, slam\_toolbox, Cartographer (robot-agnostic) | | `cyberwaveos/ros2-elevation-mapping` | GPU-accelerated elevation mapping (robot-agnostic) | The `jetson-humble` driver image ships with optimized defaults for constrained hardware. ```bash theme={null} docker pull cyberwaveos/go2-ros2-driver:jazzy docker pull cyberwaveos/ros2-nav2:jazzy docker pull cyberwaveos/ros2-slam:jazzy docker pull cyberwaveos/ros2-elevation-mapping:jazzy ``` ## Quick Start When connected to the Cyberwave platform, the **Edge Core** service automatically pulls and starts all required containers based on the asset metadata configured for your twin. For local development with Docker Compose, see the driver [README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-runtime/runtime-services/drivers/ros2/robots/unitree/go2). ## ROS 2 Topics The driver publishes standard ROS 2 topics that any ROS 2 node can consume independently: | Topic | Type | Description | | ------------------- | ------------------------- | -------------------------------- | | `/odom` | `nav_msgs/Odometry` | LiDAR-based odometry | | `/point_cloud2` | `sensor_msgs/PointCloud2` | 3D point cloud from LiDAR | | `/scan` | `sensor_msgs/LaserScan` | 2D laser scan (from point cloud) | | `/camera/image_raw` | `sensor_msgs/Image` | Front camera frames | | `/joint_states` | `sensor_msgs/JointState` | Joint positions and velocities | | `/imu/data` | `sensor_msgs/Imu` | IMU measurements | | `/map` | `nav_msgs/OccupancyGrid` | Occupancy map (from SLAM) | **All robot-specific topics are namespaced as `twin_` by default**. ## Key Environment Variables | Variable | Default | Description | | -------------------------------------------- | ------------------------------ | -------------------------------------------------------------------- | | `CYBERWAVE_API_KEY` | — | Cyberwave API token | | `CYBERWAVE_TWIN_UUID` | — | Digital twin UUID | | `CYBERWAVE_MQTT_HOST` | `mqtt.cyberwave.com` | MQTT broker | | `GO2_AES_128_KEY` | — | Per-device AES-128 key for firmware ≥ 1.1.15 (see below) | | `ROBOT_IP` | (auto-discovered) | Go2 IP — validated on startup; see below | | `ROBOT_IP_FALLBACKS` | `192.168.12.1,192.168.123.161` | Comma-separated IPs to probe when `ROBOT_IP` is unset or unreachable | | `CONFIG_PROFILE` | (auto) | Config profile: `jazzy`, `humble`, or `jetson` | | `CYBERWAVE_PERIODIC_MAP_UPLOAD_INTERVAL_SEC` | `120` | Periodic map cloud sync interval (0 to disable) | | `GO2_USE_CPP_VOXEL_DECODER` | `true` | Use C++ LiDAR decoder (faster) | | `GO2_OBSTACLE_AVOIDANCE` | `true` | Enable onboard obstacle avoidance (see below) | | `CYBERWAVE_ENABLE_RECORDING` | *(see below)* | Global recording toggle for video streams | | `CYBERWAVE_ENABLE_RECORDING_PREVIEW` | `false` | Record preview streams (occupancy, costmaps) | ### Obstacle Avoidance When `GO2_OBSTACLE_AVOIDANCE=true` (the default), velocity commands are routed through the Go2's firmware obstacle avoidance pipeline instead of the standard Sport API. The firmware fuses ultrasonic and LiDAR sensors to detect obstacles and will override velocity commands to prevent collisions. On startup the driver sends `SwitchSet` and `UseRemoteCommandFromApi` to the robot so the firmware accepts velocity commands from the ROS 2 stack rather than only the physical remote controller. Onboard obstacle avoidance operates independently from Nav2's path planner. The firmware may intervene — slowing down or stopping the robot — even when Nav2 considers the path clear. This can cause Nav2 goals to take longer or be aborted if the firmware repeatedly blocks planned motion. If you need full control over obstacle handling through Nav2's costmaps and local planner, set `GO2_OBSTACLE_AVOIDANCE=false`. To disable: ```bash theme={null} GO2_OBSTACLE_AVOIDANCE=false ``` ### Obstacle Avoidance & Teleoperation There are two layers of obstacle avoidance on the Go2: 1. **Onboard** — the robot's built-in ultrasonic + LiDAR avoidance at the firmware level. 2. **Driver-level** — path planning avoidance through costmaps constructed in real time by the navigation stack. When `GO2_OBSTACLE_AVOIDANCE=true` (configurable in the twin metadata; enabled by default), the driver activates **both layers** for autonomous navigation. **Recommended teleoperation during mapping:** * **Cyberwave keyboard controller** — obstacle avoidance is active (onboard + driver-level). This is the recommended way to drive the robot while building a map of your environment. * **Unitree physical remote** — always retains onboard obstacle avoidance regardless of driver configuration. Both options are safe for teleoperation during mapping. Bluetooth gamepad obstacle avoidance now depends on the active controller policy: * **Local Bluetooth controller (`local`)**: obstacle avoidance stays on the robot-side local controller path. * **Keyboard teleop** and **autonomous navigation**: the driver switches to the autonomy/remote-command path, and the gamepad does not keep independent obstacle avoidance. ### AES-128 Key (firmware ≥ 1.1.15) Go2 firmware **1.1.15+** uses a per-device AES-128 key (`data2=3` protocol) to encrypt the WebRTC LAN handshake. Without this key, both the driver node and native video node will fail to connect. Fetch the key using the `unitree_webrtc_connect` CLI (requires the Unitree account used in the Unitree Go/Explore mobile app): ```bash theme={null} pip install unitree_webrtc_connect unitree-fetch-aes-key --email your@email.com --password 'your-password' --device-type Go2 ``` Set the 32-hex-char key in your env file or Edge Core `shared_env`: ```bash theme={null} GO2_AES_128_KEY=abcdef0123456789abcdef0123456789 ``` Older firmware (below 1.1.15) uses a static key built into the driver and does not require this variable. If `GO2_AES_128_KEY` is unset and the robot returns `data2=3`, the driver will log a clear error with instructions. ### Robot IP discovery The driver validates that the Go2 is reachable **before** starting any ROS 2 node, so you get a fast failure instead of a silent WebRTC hang. **Resolution order:** 1. `ROBOT_IP` (from env or Edge Core metadata) — probed via TCP on port 9991. 2. If unreachable (or unset), each address in `ROBOT_IP_FALLBACKS` is tried. 3. First address that responds is used for the entire stack. 4. If nothing responds, the container exits with an error and pushes a `robot_unreachable` alert to Cyberwave (if SDK credentials are available). The default fallback list covers the two most common Go2 network configurations: | Address | Scenario | | ----------------- | ----------------------- | | `192.168.12.1` | Wi-Fi AP / USB-Ethernet | | `192.168.123.161` | Ethernet direct-connect | **Custom networks:** If your Go2 is on a different subnet (e.g. behind a router), override the fallback list: ```bash theme={null} # .env file or Edge Core shared_env ROBOT_IP_FALLBACKS=10.0.0.50,10.0.0.51 ``` You can set both `ROBOT_IP` (preferred address) and `ROBOT_IP_FALLBACKS` (safety net). If the preferred IP is unreachable, the driver automatically falls through to the fallback list. The probe uses a TCP socket connect on port 9991 (Go2 WebRTC signaling) with a 2-second timeout per address. No WebRTC handshake is attempted. Simulation launches skip the check entirely. ## Saved maps and relocalization The stack keeps its data on the edge computer under `/etc/cyberwave/ros2_go2_driver`, which the containers see as `/data`. Every finalized map is saved there as a map bundle (`/etc/cyberwave/ros2_go2_driver/map_bundles//`), together with any AprilTags seen while mapping. At start-up the stack restores the twin's latest map and relocalizes from a known tag. See [AprilTag relocalization](/robots/go2-apriltag-relocalization). ## Config Profiles | Profile | When to use | | -------- | -------------------------------------------------------------------------------------- | | `jazzy` | Default for ROS 2 Jazzy on desktop/server hardware | | `humble` | ROS 2 Humble ecosystem compatibility | | `jetson` | NVIDIA Jetson: reduced costmap resolution, increased transform tolerances, lower rates | Set `CONFIG_PROFILE=jetson` or use the `jetson-humble` Docker image which sets this automatically. ## Edge Core metadata When using **Cyberwave Edge Core** for managed deployment, the driver stack is configured through twin/asset metadata. Edge Core reads this metadata, pulls images, and injects environment variables automatically. ### Multi-container configuration The Go2 ROS 2 stack runs as multiple cooperating containers. Define the stack in `metadata.drivers` using the `services` array: ```json theme={null} { "drivers": { "linux-aarch64-jetson": { "services": [ { "image": "cyberwaveos/go2-ros2-driver:jetson-humble", "name": "driver", "command": [ "ros2", "launch", "cyberwave_go2_driver", "robot_driver.launch.py" ] }, { "image": "cyberwaveos/go2-ros2-driver:jetson-humble", "name": "bridges", "command": [ "ros2", "launch", "cyberwave_go2_driver", "robot_bridges.launch.py" ] }, { "image": "cyberwaveos/ros2-nav2:jetson-humble", "name": "nav2" }, { "image": "cyberwaveos/ros2-slam:jetson-humble", "name": "slam" } ], "shared_env": { "CONFIG_PROFILE": "jetson", "ROS_DOMAIN_ID": "0" }, "shared_params": ["--network", "host", "-v", "/data:/data"] }, "default": { "docker_image": "cyberwaveos/go2-ros2-driver:jazzy", "prefer_gpu": true } } } ``` To add a service (e.g. elevation mapping), append to the `services` array. To set the robot IP or fallback list, add them to `shared_env`: ```json theme={null} "shared_env": { "ROBOT_IP_FALLBACKS": "10.0.0.50,10.0.0.51", "CONFIG_PROFILE": "jetson" } ``` See [Drivers overview](/feature-reference/edge/drivers/overview) for the full metadata schema and [Writing compatible drivers](/feature-reference/edge/drivers/writing-compatible-drivers) for the `edge_configs` per-device pattern. ## Stream Recording The Go2 driver streams video to the Cyberwave media service via WebRTC. Each stream can request server-side recording (producing MP4 artifacts for later replay). | Variable | Default | Applies to | | ------------------------------------ | ------- | ------------------------------------------------------------ | | `CYBERWAVE_ENABLE_RECORDING` | — | All streams (global override) | | `CYBERWAVE_ENABLE_RECORDING_PREVIEW` | `false` | Preview streams only (occupancy grid, local/global costmaps) | **Default behavior** (no env vars set): * `camera_bridge` — records by default (`true`). * `occupancy_grid_bridge`, `local_costmap_bridge`, `global_costmap_bridge` — do **not** record by default. **Resolution order** per bridge: 1. `CYBERWAVE_ENABLE_RECORDING` — if set, overrides everything. 2. Per-bridge env var (e.g. `CYBERWAVE_ENABLE_RECORDING_PREVIEW`) — overrides the built-in default. 3. Built-in default. ```bash theme={null} # Record everything including previews CYBERWAVE_ENABLE_RECORDING_PREVIEW=true # Disable all recording (e.g. for development) CYBERWAVE_ENABLE_RECORDING=false ``` Recording is handled by the media service SFU, not on the edge device. Enabling recording adds negligible load to the robot's hardware. ## Jetson Performance Tuning Running the full Go2 stack on a Jetson Orin Nano (or similar constrained hardware) requires tuning runtime rates and encoder settings. Add these to your `.env` file or Edge Core `shared_env`: ```bash theme={null} # ── Runtime rates (overrides vs. defaults) ─────────────────────────── GO2_STATE_PUBLISH_HZ=15 # default 10 GO2_POINTCLOUD_MAX_POINTS=4000 # default 25000 GO2_POINTCLOUD_STREAM_FPS=1 # default 5 GO2_SCAN_ANGLE_INCREMENT=0.01745 # default 0.00872 GO2_TRAV_COSTMAP_HZ=5 # default 10 GO2_TRAV_COSTMAP_GLOBAL_HZ=0.5 # default 1 GO2_LOCAL_COSTMAP_FPS=10 # default 5 GO2_GLOBAL_COSTMAP_FPS=10 # default 2 # ── Obstacle avoidance ────────────────────────────────────────────── # Disable if Nav2 handles obstacle avoidance to save CPU. GO2_OBSTACLE_AVOIDANCE=false # default true # ── H.264 encoding ────────────────────────────────────────────────── # Jetson Orin Nano has NO hardware H.264 encoder (no NVENC). # Skip codec probing and constrain libx264 to a single thread so it # doesn't starve SLAM/Nav2. At 424x240@1fps ultrafast this uses <5% # of one core. CYBERWAVE_H264_ENCODER=libx264 # default auto CYBERWAVE_H264_PRESET=ultrafast # default veryfast CYBERWAVE_H264_BITRATE_KBPS=800 # default 2500 CYBERWAVE_H264_THREADS=1 # default 0 (unlimited) ``` These values are tuned for a Jetson Orin Nano running the full stack (driver + Nav2 + SLAM). If your board has more headroom (e.g. Orin NX) or less (e.g. other services running), you can adjust camera and pointcloud rates accordingly. ## NVIDIA Container Toolkit (Jetson / GPU) GPU-accelerated containers (simulation, video decode, elevation mapping) require the **NVIDIA Container Toolkit**. This is especially important on Jetson (L4T / JetPack) where the toolkit must be installed and the runtime registered with Docker. ```bash theme={null} # Install distribution=$(. /etc/os-release; echo $ID$VERSION_ID) curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \ sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit # Register with Docker sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker ``` On Jetson, set the NVIDIA runtime as the default so all containers get GPU access automatically: ```bash theme={null} sudo tee /etc/docker/daemon.json <<'EOF' { "default-runtime": "nvidia", "runtimes": { "nvidia": { "args": [], "path": "nvidia-container-runtime" } } } EOF sudo systemctl restart docker ``` If `nvidia-container-toolkit` is already installed but containers cannot access the GPU, re-run the `nvidia-ctk runtime configure` step, ensure `daemon.json` has the nvidia runtime, and restart Docker. # Event Storage Metrics Source: https://docs.cyberwave.com/api-reference/metrics-events Daily-bucketed row counts of stored events for a workspace. `GET /api/v1/metrics/events/{workspace}` reports row counts of stored events, bucketed by UTC day, for a single workspace. ## Path parameters | Name | Required | Description | | ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `workspace` | yes | Workspace UUID or slug. The caller must have read access (active membership, ACL role, or workspace visibility). The path segment is parsed as a UUID first; if that fails, it is looked up as a slug. | ## Query parameters | Name | Required | Description | | ----------------- | -------- | --------------------------------- | | `start_timestamp` | no | ISO-8601 lower bound (inclusive). | | `end_timestamp` | no | ISO-8601 upper bound (exclusive). | If both bounds are provided, `start_timestamp` must be earlier than `end_timestamp` (otherwise the endpoint returns `400`). ## Response ```json theme={null} { "workspace_uuid": "…", "window": { "start": "…|null", "end": "…|null" }, "telemetry": { "total": 12345, "by_event_type": { "twin_metrics_update": 9000 }, "by_day": [{ "day": "2026-05-17", "event_type": "twin_metrics_update", "count": 4000 }] }, "workflow_executions": { "total": 42, "by_workflow": { "": { "name": "pick-and-place", "count": 42 } }, "by_day": [{ "day": "…", "workflow_uuid": "…", "workflow_name": "…", "count": 42 }] }, "workflow_node_executions": { "total": "…", "by_workflow": {}, "by_day": [] }, "alerts": { "total": 3, "by_alert_type": { "calibration_needed": 2 }, "by_day": [{ "day": "…", "alert_type": "calibration_needed", "count": 2 }] } } ``` Counts are computed from raw rows in `app_twintelemetry`, `app_workflowexecution`, `app_workflownodeexecution`, and `app_alert`. The endpoint runs aggregation in the database; only summaries cross the process boundary. # Model catalog API Source: https://docs.cyberwave.com/api-reference/models/catalog Browse, register, update, and delete ML model records in your workspace. ## Overview The model catalog is the registry of ML models available in your workspace. Each record stores metadata about where the model runs (cloud, edge, hybrid), what inputs it accepts, and how to load it via the SDK. Public models are visible without authentication; private models are scoped to workspace members. Browse and load catalog rows from Python with **`cw.models`** — see [ML Models (Python SDK)](/overview/tools/models/overview). Typed **`create`** / **`update`** helpers are not on `cw.models` yet; call `POST` / `PUT` on this API or use generated `cw.api.*` wrappers until SDK methods land. | Method | Endpoint | Auth | Description | | -------- | -------------------------- | :--: | ---------------------------------------- | | `GET` | `/api/v1/mlmodels` | ✓ | List models in your workspace (+ public) | | `GET` | `/api/v1/mlmodels/public` | — | List public models (no auth required) | | `GET` | `/api/v1/mlmodels/by-slug` | — | Get a model by unified slug | | `GET` | `/api/v1/mlmodels/{uuid}` | ✓ | Get a model by UUID | | `POST` | `/api/v1/mlmodels` | ✓ | Create a model record | | `PUT` | `/api/v1/mlmodels/{uuid}` | ✓ | Update a model record | | `DELETE` | `/api/v1/mlmodels/{uuid}` | ✓ | Delete a model record | *** ## `GET /api/v1/mlmodels` List all ML model records visible to the authenticated user: workspace-private models plus any public ones. ### Query parameters | Parameter | Type | Description | | ------------------- | -------- | -------------------------------------------------------------- | | `deployment` | `string` | Filter by deployment (`cloud`, `edge`, `hybrid`) | | `edge_compatible` | `bool` | When `true`, return only `edge` or `hybrid` models | | `model_external_id` | `string` | Filter by exact external ID (e.g. `"yolov8n.pt"`) | | `supported_level` | `string` | Filter by `driver`, `cloud`, `backend`, or `not_supported_yet` | | `is_trainable` | `bool` | Filter trainable models only | ### Response — `200 OK` Array of [MLModelSchema](#mlmodelschema). ```json theme={null} [ { "uuid": "a1b2c3d4-...", "slug": "acme/models/yolo26n", "name": "YOLO26n", "description": "Compact YOLO26 nano — 320 px, 4.4 ms CPU", "deployment": "edge", "is_edge_compatible": true, "is_cloud_compatible": false, "sdk_load_id": "yolo26n.pt", "model_external_id": "yolo26n.pt", "model_provider_name": "ultralytics", "edge_runtime": "ultralytics", "can_take_image_as_input": true, "can_take_video_as_input": true, "can_take_text_as_input": false, "can_take_audio_as_input": false, "can_take_action_as_input": false, "is_trainable": false, "visibility": "public", "tags": ["yolo", "detection"], "output_format": "json", "output_family": "structured_perception", "playground_kind": "edge", "workspace_uuid": "ws-uuid-...", "created_at": "2026-01-10T08:00:00Z", "updated_at": "2026-04-01T12:00:00Z" } ] ``` *** ## `GET /api/v1/mlmodels/public` List all public models. No authentication required. Accepts the same `deployment` query parameter as the authenticated list endpoint. *** ## `GET /api/v1/mlmodels/by-slug` Retrieve a model by its unified slug (`{workspace-slug}/models/{entity-slug}`). Anonymous callers see public models. Authenticated callers additionally see private models they have access to. ### Query parameters | Parameter | Type | Description | | --------- | --------------------- | --------------------------------------------- | | `slug` | `string` **required** | Full unified slug, e.g. `acme/models/yolo26n` | ### Response codes | Code | Meaning | | ----- | ----------------------------------------------------- | | `200` | Model found — returns [MLModelSchema](#mlmodelschema) | | `404` | Model not found or not visible to caller | *** ## `GET /api/v1/mlmodels/{uuid}` Get a single model by UUID. Requires read access. ### Path parameters | Parameter | Description | | --------- | ----------- | | `uuid` | Model UUID | *** ## `POST /api/v1/mlmodels` Create a new ML model record. Only admins can create `public` models. ### Request body — `MLModelCreateSchema` | Field | Type | Default | Description | | -------------------------- | --------------------- | ----------- | ----------------------------------------------------------------------- | | `name` | `string` **required** | — | Human-readable model name | | `description` | `string` **required** | — | Description | | `model_external_id` | `string` **required** | — | Filename or external registry key (e.g. `"yolov8n.pt"`) | | `model_provider_name` | `string` **required** | — | Provider label (e.g. `"ultralytics"`, `"openai"`, `"local"`) | | `deployment` | `string` | `"cloud"` | `cloud`, `edge`, or `hybrid` | | `visibility` | `string` | `"private"` | `private`, `workspace`, `org`, `link`, or `public` | | `workspace_uuid` | `string` | auto | Target workspace; omit to use the preferred workspace | | `slug` | `string` | auto | Custom slug; auto-generated from name when omitted | | `is_trainable` | `bool` | `false` | Whether the model supports fine-tuning | | `can_take_image_as_input` | `bool` | `false` | | | `can_take_video_as_input` | `bool` | `false` | | | `can_take_text_as_input` | `bool` | `true` | | | `can_take_audio_as_input` | `bool` | `false` | | | `can_take_action_as_input` | `bool` | `false` | | | `edge_runtime` | `string` | `null` | Well-known runtime key (see `GET /mlmodels/edge-runtimes`) or free-text | | `tags` | `string[]` | `[]` | Searchable tags | | `metadata` | `object` | `{}` | Arbitrary metadata bag | | `mapped_model_id` | `string` | `null` | Provider-internal model ID | | `output_format` | `string` | `null` | Output format hint (`json`, `image`, `action`, …) | ### Example request ```json theme={null} { "name": "YOLOv8 Nano", "description": "Lightweight object detector for warehouse inspection", "model_external_id": "yolov8n.pt", "model_provider_name": "ultralytics", "deployment": "edge", "edge_runtime": "ultralytics", "can_take_image_as_input": true, "can_take_video_as_input": true, "tags": ["detection", "vision"] } ``` ### Response — `200 OK` Returns the created [MLModelSchema](#mlmodelschema). *** ## `PUT /api/v1/mlmodels/{uuid}` Update a model. Write access required. Only admins can change visibility to/from `public`. ### Request body — `MLModelUpdateSchema` All fields are optional. Omitting a field leaves it unchanged. | Field | Type | Notes | | --------------------- | ---------- | -------------------------------- | | `name` | `string` | | | `description` | `string` | | | `model_external_id` | `string` | | | `model_provider_name` | `string` | | | `deployment` | `string` | `cloud`, `edge`, `hybrid` | | `visibility` | `string` | Admin-only for `public` changes | | `is_trainable` | `bool` | | | `can_take_*_as_input` | `bool` | Any input capability flag | | `edge_runtime` | `string` | Pass `""` to clear | | `tags` | `string[]` | Replaces the entire tag list | | `metadata` | `object` | Replaces the entire metadata bag | | `mapped_model_id` | `string` | | | `output_format` | `string` | | *** ## `DELETE /api/v1/mlmodels/{uuid}` Delete a model record. Write access required. Only admins can delete public models. ### Response — `200 OK` ```json theme={null} { "success": true } ``` *** ## MLModelSchema Full model record returned by all read endpoints. | Field | Type | Description | | -------------------------- | ---------------- | ------------------------------------------------------------------------------ | | `uuid` | `string` | UUID | | `slug` | `string \| null` | Unified slug — `{workspace}/models/{name}` | | `name` | `string` | Human-readable name | | `description` | `string` | | | `model_external_id` | `string` | Filename or external ID | | `model_provider_name` | `string` | Provider label | | `deployment` | `string` | `cloud`, `edge`, or `hybrid` | | `is_edge_compatible` | `bool` | True when deployment is `edge` or `hybrid` | | `is_cloud_compatible` | `bool` | True when deployment is `cloud` or `hybrid` | | `sdk_load_id` | `string \| null` | Key to pass to `cw.models.load()` | | `edge_runtime` | `string \| null` | Runtime/framework label (e.g. `ultralytics`, `onnx`) | | `edge_catalog_id` | `string \| null` | Resolved edge catalog ID (equals `sdk_load_id` for edge models) | | `playground_kind` | `string \| null` | UI playground variant: `vlm`, `vlm-spatial-reasoner`, `vla`, `im2mesh`, `edge` | | `output_format` | `string \| null` | Raw output format hint | | `output_family` | `string \| null` | Canonical family: `structured_perception`, `action`, `text`, `image`, `mesh` | | `visibility` | `string` | `private`, `workspace`, `org`, `link`, `public` | | `tags` | `string[]` | | | `is_trainable` | `bool` | | | `can_take_image_as_input` | `bool` | | | `can_take_video_as_input` | `bool` | | | `can_take_text_as_input` | `bool` | | | `can_take_audio_as_input` | `bool` | | | `can_take_action_as_input` | `bool` | | | `allowed_structured_tasks` | `string[]` | Playground structured task IDs available for this model | | `execution_surfaces` | `string[]` | Where the model can execute (`playground`, `edge_worker`, …) | | `workspace_uuid` | `string` | Owner workspace | | `created_at` | `datetime` | | | `updated_at` | `datetime` | | *** ## Python SDK ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() # List for m in cw.models.list(): print(m.slug, m.deployment, m.sdk_load_id) # Filter by deployment for m in cw.models.list(deployment="edge"): print(m.slug) # Public models (no auth needed) for m in cw.models.list_public(): print(m.slug) # Get by slug or UUID m = cw.models.get("acme/models/yolo26n") m = cw.models.get_by_uuid("a1b2c3d4-...") # Delete cw.models.delete("a1b2c3d4-...") # Create / update — call the raw API client cw.api.src_app_api_mlmodels_create_mlmodel( ml_model_create_schema={ "name": "YOLOv8n", "description": "Edge detector", "model_external_id": "yolov8n.pt", "model_provider_name": "ultralytics", "deployment": "edge", } ) ``` ## MCP tools ``` cw_list_models(workspace_uuid?, deployment?) cw_get_model(model_uuid) cw_delete_model(model_uuid, execute?) ``` *** ## Related Run inference, evaluate, download weights SDK reference for catalog + runtime Run edge models on hardware Dashboard walkthrough # Model playground API Source: https://docs.cyberwave.com/api-reference/models/playground Run inference, evaluate on benchmarks, and download model weights — endpoint reference with request/response schemas. ## Overview The Model Playground provides three API surfaces for working with model inference: | Method | Endpoint | Auth | Description | | ------ | ------------------------------------- | :--: | ------------------------------------------------------ | | `POST` | `/api/v1/mlmodels/{uuid}/run` | ✓ | Run the model synchronously or queue an async workload | | `POST` | `/api/v1/mlmodels/{uuid}/evaluate` | ✓ | Start a benchmark evaluation run | | `GET` | `/api/v1/mlmodels/{uuid}/weights` | ✓ | Get a signed URL for the model's checkpoint weights | | `GET` | `/api/v1/mlmodels/structured-actions` | — | List available structured task IDs (public) | | `GET` | `/api/v1/mlmodels/edge-runtimes` | — | List well-known edge runtime options (public) | *** ## `POST /api/v1/mlmodels/{uuid}/run` Run a model interactively. Used by the in-app playground and directly from the SDK. **Sync path (200):** Direct provider call (Google GenAI, OpenAI, or a custom HTTP endpoint). **Async path (202):** Used when a cloud-node workload is required (e.g. `im2mesh`, audio). Returns a `workload_uuid` to poll. Edge-only models (`is_edge_compatible && !is_cloud_compatible`) are rejected with `400` from this endpoint. Use the Python SDK (`cw.models.load(entry).predict(...)`) or the `cyberwave model bind` CLI instead. ### Request body — `MLModelRunSchema` At least one of `prompt`, `image_base64`, or `image_url` must be provided for most model types. #### Core inputs | Field | Type | Description | | ----------------- | -------- | ---------------------------------------------------------------------- | | `prompt` | `string` | Text prompt | | `image_base64` | `string` | Base64-encoded image (data URI or raw) | | `image_url` | `string` | Publicly accessible image URL | | `audio_base64` | `string` | Base64-encoded audio (audio runs are async) | | `audio_url` | `string` | Publicly accessible audio URL | | `language` | `string` | Language hint for speech/translation tasks | | `task` | `string` | Generic task hint passed to the provider | | `structured_task` | `string` | Structured task ID from `/mlmodels/structured-actions` | | `twin_uuid` | `string` | When set, backend auto-pulls the twin's latest state for VLA/IK models | | `params` | `object` | Provider-specific parameters (e.g. `temperature`, `max_tokens`) | #### Extended perception envelope (optional) These fields let runners build richer spatial context without a second API revision: | Field | Type | Description | | ------------------- | ------------------------ | -------------------------------------------------------------------------------------------------- | | `frames` | `MLModelFrameSchema[]` | Ordered extra frames (wrist + overhead views, short clips). `image_base64`/`image_url` is frame 0. | | `depth_base64` | `string` | 16-bit PNG depth map aligned to the primary frame | | `camera_intrinsics` | `CameraIntrinsicsSchema` | Pinhole intrinsics (`fx`, `fy`, `cx`, `cy`, `width`, `height`) | | `camera_pose` | `CameraPoseSchema` | World pose of the primary camera (position + quaternion) | | `history` | `HistoryTurnSchema[]` | Prior conversation/context turns for stateful perception | | `robot_state` | `RobotStateSchema` | Robot joint state + gripper state. Server auto-fills from `twin_uuid` when omitted. | | `robot_context` | `RobotContextSchema` | Embodiment context (schema, capabilities summary) | #### `MLModelFrameSchema` | Field | Type | Description | | -------------- | -------- | ------------------------------------------ | | `image_base64` | `string` | Base64 image | | `image_url` | `string` | Image URL | | `timestamp` | `int` | Monotonic ms offset from first frame | | `camera_id` | `string` | Camera label, e.g. `"wrist"`, `"overhead"` | ### Response — `200 OK` (sync) ```json theme={null} { "status": "completed", "output_format": "json", "output": [ { "label": "box", "confidence": 0.94, "bbox": [120, 45, 380, 290] } ], "raw": "...", "actions": null } ``` #### `MLModelRunResultSchema` | Field | Type | Description | | --------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `status` | `string` | Always `"completed"` | | `output_format` | `string` | See [Output formats](#output-formats) below | | `output` | `any` | Parsed model output — type depends on `output_format` | | `raw` | `string \| null` | Raw provider response (for debugging) | | `actions` | `MotionEpisodeSchema \| null` | Server-resolved motion episode when the runner computed it directly (VLA / spatial reasoners). `null` for bare perception responses. | ### Response — `202 Accepted` (async / cloud-node) ```json theme={null} { "status": "queued", "workload_uuid": "w1b2c3d4-...", "poll_url": "/api/v1/cloud-node-workloads/w1b2c3d4-..." } ``` Poll `GET /api/v1/cloud-node-workloads/{workload_uuid}` until `status == "completed"`. The result payload lands in `workload.command_params.result`. ### Response codes | Code | Meaning | | ----- | --------------------------------------------------------------- | | `200` | Inference completed — response body is `MLModelRunResultSchema` | | `202` | Workload queued — poll `poll_url` | | `400` | Edge-only model, bad payload, or provider error | | `403` | Model not accessible or feature flag not enabled | *** ## Output formats The `output_format` field in the run result tells you how to interpret `output`: | `output_format` | `output` type | Description | | ---------------- | -------------------- | --------------------------------------------------------------- | | `text` | `string` | Plain text response | | `json` | `object` | Arbitrary structured JSON | | `image` | `string` | Data URL (`data:image/...;base64,...`) | | `points` | `[[y, x], …]` | Normalized 0-1000 point coordinates (Gemini ER / spatial tasks) | | `boxes` | `[[y1,x1,y2,x2], …]` | Normalized 0-1000 bounding boxes | | `masks` | `object[]` | Segmentation masks | | `detections_3d` | `object[]` | 3D bounding boxes with position + orientation | | `grasps` | `object[]` | Grasp candidates (position, orientation, width) | | `trajectory` | `object[]` | Planned end-effector trajectory | | `plan_steps` | `object[]` | High-level plan steps | | `relations` | `object[]` | Detected spatial relations between objects | | `mesh` | `string` | GLB URL (for `im2mesh` models) | | `motion_episode` | `object` | Recorded or generated motion episode | | `raw` | `string` | Unprocessed provider output | ### Example: VLM text response ```json theme={null} { "status": "completed", "output_format": "text", "output": "The robot arm is above the red cube." } ``` ### Example: Spatial reasoner — points ```json theme={null} { "status": "completed", "output_format": "points", "output": [ [312, 450], [680, 210] ] } ``` Points are `[y, x]` normalized to 0-1000, where `[0, 0]` is the top-left corner. ### Example: Detections (structured\_task = `"detect_objects"`) ```json theme={null} { "status": "completed", "output_format": "json", "output": [ { "label": "bottle", "confidence": 0.92, "bbox": [50, 120, 200, 480] }, { "label": "cup", "confidence": 0.88, "bbox": [310, 95, 420, 360] } ] } ``` *** ## `POST /api/v1/mlmodels/{uuid}/evaluate` Start an asynchronous benchmark evaluation. Returns `202 Accepted` immediately with a poll URL. ### Request body — `MLModelEvaluateSchema` | Field | Type | Default | Description | | ---------------- | -------- | ----------------------- | ------------------------------ | | `benchmark_slug` | `string` | `"perception-smoke-v1"` | Benchmark suite to run against | ### Response — `202 Accepted` ```json theme={null} { "status": "queued", "workload_uuid": "e1f2a3b4-...", "poll_url": "/api/v1/cloud-node-workloads/e1f2a3b4-..." } ``` Poll `GET /api/v1/cloud-node-workloads/{uuid}` until `status == "completed"`. Results are in `workload.command_params.result` — aggregate pass rate and per-case breakdown. To list available benchmark suites: `GET /api/v1/mlmodels/benchmark-suites` (public, no auth). *** ## `GET /api/v1/mlmodels/{uuid}/weights` Get a signed download URL for the model's checkpoint weights (tar archive containing `config.json` + adapter files from training). ### Response — `200 OK` ```json theme={null} { "signed_url": "https://storage.googleapis.com/...?Expires=...", "expires_at": "2026-05-14T22:00:00+00:00", "checkpoint_path": "models/a1b2c3d4/.../checkpoint.tar" } ``` The signed URL is valid for **2 hours**. ### Response codes | Code | Meaning | | ----- | ----------------------------------------------------------- | | `200` | Signed URL generated | | `404` | Model has no checkpoint, or checkpoint not found in storage | *** ## `GET /api/v1/mlmodels/structured-actions` Return the canonical catalog of `structured_task` values understood by the playground. No authentication required. Consumed by the frontend and Python SDK. ```json theme={null} { "detect_objects": { "label": "Detect objects", "description": "...", "output_format": "json" }, "detect_points": { "..." }, "caption": { "..." } } ``` *** ## Python SDK Two patterns map to this API: **1 — Playground handle** (`POST /api/v1/mlmodels/{uuid}/run` with full request control): ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() handle = cw.models.playground("acme/models/gemini-robotics-er") # Returns MLModelRunResultSchema or MLModelRunQueuedSchema (not PredictionResult) result = handle.run( image="scene.jpg", prompt="Point to the red cube", structured_task="detect_points", ) ``` **2 — Unified `load()` + `predict()`** (routes cloud slugs through the playground-backed inference path where applicable; edge weights run locally): ```python theme={null} from cyberwave import Cyberwave from PIL import Image cw = Cyberwave() img = Image.open("frame.jpg").convert("RGB") entry = cw.models.list(deployment="cloud")[0] model = cw.models.load(entry) # or cw.models.load("acme/models/…") pred = model.predict(img, confidence=0.25) print(pred.describe()) ``` For edge-only weights, **`load().predict()`** runs on-device; **`playground(...).run()`** is for the HTTP playground contract (prompts, structured tasks, async workloads). *** ## cURL examples ### Text-only VLM run ```bash theme={null} curl -X POST "$CYBERWAVE_BASE_URL/api/v1/mlmodels/$MODEL_UUID/run" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "What objects do you see on the workbench?"}' ``` ### Vision run with image URL ```bash theme={null} curl -X POST "$CYBERWAVE_BASE_URL/api/v1/mlmodels/$MODEL_UUID/run" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Detect all boxes", "image_url": "https://example.com/workspace_frame.jpg", "structured_task": "detect_objects" }' ``` ### Spatial reasoning run (points) ```bash theme={null} curl -X POST "$CYBERWAVE_BASE_URL/api/v1/mlmodels/$MODEL_UUID/run" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Point to the red cube", "image_url": "https://example.com/scene.jpg", "structured_task": "detect_points" }' ``` *** ## Related Browse and manage model records SDK reference for catalog + runtime All available structured task IDs Run edge models on hardware # MQTT API reference Source: https://docs.cyberwave.com/api-reference/mqtt/main Complete reference for all MQTT topics and payload schemas used by the Cyberwave platform. The Cyberwave platform uses MQTT for real-time communication between edge drivers, the cloud backend, and the frontend. This page lists every topic and payload schema so you can write compatible drivers, simulators, or integrations without reading source code. ## Topic prefix In non-production deployments the broker may be configured with an environment prefix (e.g. `local` for local dev). When a prefix is set, every topic below is written `{prefix}cyberwave/...`. The Python SDK's `topic_prefix` parameter and the `CYBERWAVE_MQTT_TOPIC_PREFIX` environment variable handle this automatically (when neither is set, the SDK derives the prefix from `CYBERWAVE_ENVIRONMENT`). All topic patterns on this page omit the prefix for clarity. ## Source types Most payloads include a `source_type` field. The allowed values are: | Value | Meaning | | --------------- | ------------------------------------ | | `edge` | Physical edge device / driver | | `edge_leader` | Leader arm (teleoperation) | | `edge_follower` | Follower arm (teleoperation) | | `tele` | Frontend teleoperation (real-world) | | `sim` | Simulation state (e.g. MuJoCo) | | `sim_tele` | Frontend teleoperation in simulation | | `edit` | Frontend editor and preview mode | *** ## Twin transform ### `cyberwave/twin/{twin_uuid}/position` **Direction:** publish (edge / sim) → subscribe (backend, frontend) Reports the 3D world position of the twin. Published by edge drivers and simulators; consumed by the backend (Vector) and the frontend. ```json theme={null} { "source_type": "edge", "position": { "x": 1.0, "y": 2.0, "z": 0.0 }, "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------- | | `source_type` | string | yes | See [source types](#source-types) | | `position.x` | number | yes | X coordinate (metres) | | `position.y` | number | yes | Y coordinate (metres) | | `position.z` | number | yes | Z coordinate (metres) | | `timestamp` | number | no | Unix timestamp (seconds) | *** ### `cyberwave/twin/{twin_uuid}/rotation` **Direction:** publish (edge / sim) → subscribe (backend, frontend) Reports the orientation of the twin as a quaternion. ```json theme={null} { "source_type": "edge", "rotation": { "w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0 }, "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------- | | `source_type` | string | yes | See [source types](#source-types) | | `rotation.w` | number | no | W component (real part, default `1.0`) | | `rotation.x` | number | no | X component (default `0.0`) | | `rotation.y` | number | no | Y component (default `0.0`) | | `rotation.z` | number | no | Z component (default `0.0`) | | `timestamp` | number | no | Unix timestamp (seconds) | *** ### `cyberwave/twin/{twin_uuid}/scale` **Direction:** publish (edge / editor) → subscribe (backend, frontend) Sets the render scale of the twin's 3D model. ```json theme={null} { "source_type": "edit", "scale": { "x": 1.0, "y": 1.0, "z": 1.0 }, "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------- | | `source_type` | string | yes | See [source types](#source-types) | | `scale.x` | number | yes | X scale factor | | `scale.y` | number | yes | Y scale factor | | `scale.z` | number | yes | Z scale factor | | `timestamp` | number | no | Unix timestamp (seconds) | *** ## Joint states ### `cyberwave/joint/{twin_uuid}/update` **Direction:** publish (edge / sim / tele) → subscribe (backend, frontend) Reports the state of one or more joints. Two payload formats are supported. #### Single-joint format Use this to report one joint at a time. ```json theme={null} { "source_type": "edge", "type": "joint_state", "joint_name": "shoulder_pan", "joint_state": { "position": 1.57, "velocity": 0.0, "effort": 0.0 }, "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ---------------------- | ------ | -------- | ---------------------------------------------------- | | `source_type` | string | yes | See [source types](#source-types) | | `type` | string | yes | Always `"joint_state"` | | `joint_name` | string | yes | Joint name as defined in the asset schema | | `joint_state.position` | number | no | Position in radians (revolute) or metres (prismatic) | | `joint_state.velocity` | number | no | Velocity | | `joint_state.effort` | number | no | Effort / torque | | `timestamp` | number | no | Unix timestamp (seconds) | #### Flat multi-joint format Use this to report many joints efficiently. Joint positions become top-level keys. ```json theme={null} { "source_type": "edge", "_1": 0.5, "_2": -0.3, "_3": 1.2 } ``` | Field | Type | Required | Description | | -------------- | ------ | -------- | --------------------------------------------------------- | | `source_type` | string | yes | See [source types](#source-types) | | `{joint_name}` | number | yes | One key per joint; value is position in radians or metres | #### Aggregated multi-joint format Use this when you also want to send velocities, efforts, or telemetry metadata. ```json theme={null} { "source_type": "edge_follower", "positions": { "_1": 0.5, "_2": -0.3 }, "velocities": { "_1": 0.0, "_2": 0.0 }, "efforts": { "_1": 0.0, "_2": 0.0 }, "timestamp": 1709123456.789, "source_subtype": "openvla", "workload_uuid": "uuid-here" } ``` | Field | Type | Required | Description | | ---------------- | ------ | ---------------------------- | ----------------------------------------------- | | `source_type` | string | yes | See [source types](#source-types) | | `positions` | object | yes | Map of joint names to position values | | `velocities` | object | no | Map of joint names to velocity values | | `efforts` | object | no | Map of joint names to effort values | | `timestamp` | number | yes (when using this format) | Unix timestamp (seconds) | | `source_subtype` | string | no | Inference model name (e.g. `"openvla"`) | | `workload_uuid` | string | no | UUID of the ML workload generating this update | | `session_id` | string | no | Session identifier for grouping related updates | *** ## Navigation ### `cyberwave/twin/{twin_uuid}/navigate/command` **Direction:** publish (backend) → subscribe (edge driver) Sends a navigation command to the robot. Published by the backend in response to a REST API call. The current payload uses Cartesian coordinates. The proposed extension for supporting both Cartesian and GPS-native vehicles is documented in [Navigation Coordinate Convention](/feature-reference/edge/drivers/navigation-coordinate-convention). ```json theme={null} { "action_id": "d0b0e8a7-7d6e-4e73-bf2d-9c420ff14c75", "command": "navigate_to_pose", "twin_uuid": "twin-uuid-here", "environment_uuid": "env-uuid-here", "controller_policy_uuid": "policy-uuid-here", "source_type": "tele", "nav_frame_coords": false, "position": [1.0, 2.0, 0.0], "rotation": [0.0, 0.0, 0.0, 1.0], "waypoints": [{ "x": 0.5, "y": 1.0, "z": 0.0 }], "constraints": {}, "frame_id": "map", "reference_frame": "map", "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ------------------------ | --------- | -------- | ----------------------------------------------------------------- | | `action_id` | string | yes | UUID of the action (use to report status back) | | `command` | string | yes | Navigation command string (e.g. `"navigate_to_pose"`, `"cancel"`) | | `twin_uuid` | string | yes | UUID of the twin to navigate | | `environment_uuid` | string | no | UUID of the environment | | `controller_policy_uuid` | string | no | UUID of the controller policy | | `source_type` | string | yes | See [source types](#source-types) | | `nav_frame_coords` | boolean | yes | Whether coordinates are already in the navigation frame | | `position` | array\[3] | no | Target position `[x, y, z]` in metres | | `rotation` | array\[4] | no | Target orientation as quaternion `[x, y, z, w]` | | `waypoints` | array | no | List of intermediate waypoints `{x, y, z}` | | `constraints` | object | no | Navigation constraints (planner-specific) | | `frame_id` | string | no | Coordinate frame for the target | | `reference_frame` | string | no | Same as `frame_id` | | `metadata` | object | no | Extra metadata forwarded to the driver | | `timestamp` | number | yes | Unix timestamp (seconds) | ### `cyberwave/twin/{twin_uuid}/navigate/status` **Direction:** publish (edge driver) → subscribe (backend) Reports the execution status of a navigation command. The `action_id` must match the one received in `navigate/command`. ```json theme={null} { "action_id": "d0b0e8a7-7d6e-4e73-bf2d-9c420ff14c75", "status": "running", "progress": 45.0, "source_type": "edge", "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------------------------------------------------------------------- | | `action_id` | string | yes | Action UUID received in the command | | `status` | string | yes | `"queued"` \| `"running"` \| `"blocked"` \| `"completed"` \| `"failed"` \| `"cancelled"` | | `message` | string | no | Human-readable status message | | `progress` | number | no | Completion percentage (0–100) | | `source_type` | string | no | See [source types](#source-types) | | `timestamp` | number | no | Unix timestamp (seconds) | *** ## Locomotion commands ### `cyberwave/twin/{twin_uuid}/command` **Direction:** publish (backend / frontend) → subscribe (edge driver) Sends a discrete command to an edge device. Used for locomotion (move/turn), video control, and robot-specific actions. #### Locomotion commands Sent by the Cyberwave platform when the user presses a keyboard binding. ```json theme={null} { "source_type": "tele", "command": "move_forward", "data": { "linear_x": 1.5, "angular_z": 0.0 }, "timestamp": 1700000000.0 } ``` Standard locomotion command strings: | `command` | Description | `data` fields | | ---------------- | -------------------------------- | ------------------------------------------------- | | `move_forward` | Drive forward | `linear_x` (m/s or m), `angular_z` (rad/s or rad) | | `move_backward` | Drive backward | `linear_x` (negative), `angular_z` | | `turn_left` | Rotate left | `linear_x: 0`, `angular_z` (positive) | | `turn_right` | Rotate right | `linear_x: 0`, `angular_z` (negative) | | `strafe_left` | Strafe left (drones/omni robots) | `linear_y` (negative) | | `strafe_right` | Strafe right | `linear_y` (positive) | | `ascend` | Increase altitude (drones) | `linear_z` (positive) | | `descend` | Decrease altitude | `linear_z` (negative) | | `takeoff` | Take off | — | | `land` | Land | — | | `return_to_home` | Return to home position | — | | `emergency_stop` | Immediate stop | — | | `sit_down` | Sit / crouch (quadruped) | `delta_z` (negative) | | `stand_up` | Stand (quadruped) | `delta_z` (positive) | | `recovery_stand` | Recovery stand (quadruped) | — | Robot-specific command strings used by bundled controllers: | `command` | Robot | Description | | ------------------------------ | -------------------- | -------------------------------------------------------------------------------------------------- | | `led_toggle` | Quadruped | Toggle LEDs | | `chassis_light_toggle` | UGV Beast | Toggle chassis light | | `camera_light_toggle` | UGV Beast | Toggle camera light | | `camera_up` / `camera_down` | UGV Beast | Tilt camera | | `camera_left` / `camera_right` | UGV Beast | Pan camera | | `camera_default` | UGV Beast | Reset camera position | | `take_photo` | UGV Beast, Quadruped | Trigger camera snapshot (result published to [`camera/photo`](#cyberwavetwintwin_uuidcameraphoto)) | | `battery_check` | UGV Beast | Request battery status | | `lights` | UGV Beast | Set light PWM (pass `pwm` in `data`) | | `set_linear_velocity` | Quadruped | Update velocity setting (`linear` in `data`) | | `set_angular_velocity` | Quadruped | Update velocity setting (`angular` in `data`) | | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------ | | `source_type` | string | yes | See [source types](#source-types) | | `command` | string | yes | Command name (see tables above) | | `data` | object | no | Command parameters (driver-specific) | | `timestamp` | number | yes | Unix timestamp (seconds) | #### Video control commands Sent by the backend to start or stop video streaming on the edge device. ```json theme={null} { "type": "start_video", "timestamp": 1700000000.0, "sensor_id": "front_camera", "recording": true } ``` | Field | Type | Required | Description | | ----------- | ------- | -------- | ---------------------------------------------------------------------- | | `type` | string | yes | `"start_video"` \| `"stop_video"` | | `timestamp` | number | yes | Unix timestamp (seconds) | | `sensor_id` | string | no | Camera identifier for multi-camera setups (defaults to primary camera) | | `recording` | boolean | no | Whether to record the stream (`start_video` only) | *** ## Telemetry lifecycle ### `cyberwave/twin/{twin_uuid}/telemetry` **Direction:** publish (edge driver) → subscribe (backend) Lifecycle events for the telemetry session. Send these to let the backend track driver connectivity. ```json theme={null} { "type": "connected", "timestamp": 1700000000.0 } { "type": "telemetry_start", "timestamp": 1700000000.0, "fps": 30.0 } { "type": "telemetry_end", "timestamp": 1700000000.0 } { "type": "disconnected", "timestamp": 1700000000.0 } ``` | `type` | When to send | Extra fields | | --------------------- | --------------------------------------------------------- | ------------------------------------------- | | `connected` | On MQTT connect | — | | `telemetry_start` | When the driver starts publishing data | `fps` (optional), `observations` (optional) | | `telemetry_end` | When the driver stops publishing data | — | | `disconnected` | On MQTT disconnect | — | | `initial_observation` | For teleoperation: send current joint state to the leader | `observations` (object), `fps` (number) | Other `type` values used internally by edge drivers: | `type` | Description | | ----------------------- | ----------------------------------------------------------------------- | | `camera_stored` | Camera frame stored to recording | | `video_start_timestamp` | Timestamp of first video frame | | `camera_sync_frame` | Frame used to synchronise camera playback | | `driver_log` | Driver log message (see [driver log](#cyberwavetwintwin_uuiddriverlog)) | | `motor_status` | Motor controller status | *** ## Sensor data ### `cyberwave/twin/{twin_uuid}/depth` **Direction:** publish (edge driver) → subscribe (backend / cloud nodes) Depth camera frame as a base64-encoded array. ```json theme={null} { "type": "depth_data", "data": "base64EncodedDepthArray==", "width": 640, "height": 480, "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ----------- | ------ | -------- | ----------------------------------------------- | | `type` | string | yes | Always `"depth_data"` | | `data` | string | yes | Base64-encoded uint16 depth array (millimetres) | | `width` | number | no | Frame width in pixels (default `640`) | | `height` | number | no | Frame height in pixels (default `480`) | | `timestamp` | number | no | Unix timestamp (seconds) | ### `cyberwave/twin/{twin_uuid}/pointcloud` **Direction:** publish (backend / edge) → subscribe (frontend) Point cloud data as a base64-encoded array. ```json theme={null} { "type": "pointcloud", "data": "base64EncodedPointCloud==", "timestamp": 1700000000.0 } ``` | Field | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------------ | | `type` | string | yes | Always `"pointcloud"` | | `data` | string | yes | Base64-encoded Nx3 float32 XYZ array | | `timestamp` | number | no | Unix timestamp (seconds) | ### `cyberwave/twin/{twin_uuid}/camera/photo` **Direction:** publish (edge driver) → subscribe (backend / frontend / SDK clients) A single still image captured on demand. This is the **result** of a [`take_photo`](#cyberwavetwintwin_uuidcommand) command: 1. A client (frontend keyboard control, or your own code) publishes `{ "command": "take_photo" }` to `cyberwave/twin/{twin_uuid}/command`. 2. The driver grabs the current camera frame, JPEG-encodes it (downscaled to keep the payload small), and base64-encodes the bytes. 3. The driver publishes the payload below to `cyberwave/twin/{twin_uuid}/camera/photo`. The camera does **not** need to be streaming video for this to work — the driver captures a frame on demand. ```json theme={null} { "source_type": "edge", "timestamp": 1700000000.0, "image": "base64EncodedJpeg==", "format": "jpeg", "width": 1280, "height": 720 } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------------------------- | | `source_type` | string | yes | Always `"edge"` (see [source types](#source-types)) | | `image` | string | yes | Base64-encoded image bytes (decode to get the file) | | `format` | string | yes | Image encoding, always `"jpeg"` | | `width` | number | no | Frame width in pixels | | `height` | number | no | Frame height in pixels | | `timestamp` | number | no | Unix timestamp (seconds) | #### Retrieving the photo Subscribe to the topic, then base64-decode the `image` field. Remember to prepend the [topic prefix](#topic-prefix) in non-production deployments (e.g. `localcyberwave/twin/...`). ```python theme={null} import base64, json import paho.mqtt.client as mqtt TWIN_UUID = "your-twin-uuid" def on_message(client, userdata, msg): payload = json.loads(msg.payload) if payload.get("source_type") != "edge" or not payload.get("image"): return with open("photo.jpg", "wb") as f: f.write(base64.b64decode(payload["image"])) print(f"Saved {payload['width']}x{payload['height']} photo") client = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2) client.username_pw_set(username="", password="") # see Integration surfaces client.tls_set() client.on_message = on_message client.connect("mqtt.cyberwave.com", 8883) # Trigger the capture, then wait for the result. client.subscribe(f"cyberwave/twin/{TWIN_UUID}/camera/photo") client.publish( f"cyberwave/twin/{TWIN_UUID}/command", json.dumps({"source_type": "tele", "command": "take_photo", "timestamp": 0}), ) client.loop_forever() ``` *** ### `cyberwave/twin/{twin_uuid}/metrics` **Direction:** publish (edge driver) → subscribe (backend) Periodic robot metrics snapshot (battery, navigation status, load, errors, etc.). ```json theme={null} { "source_type": "edge", "metrics": { "power": { "battery_percent": 78, "charging": false, "voltage": 48.2, "estimated_runtime_minutes": 240 }, "navigation": { "status": "navigating", "distance_remaining_m": 23.5, "eta_seconds": 45 }, "errors": [] } } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------------------------- | | `source_type` | string | yes | Typically `"edge"` | | `metrics` | object | yes | Free-form dict of metric categories and values | *** ## Edge health ### `cyberwave/twin/{twin_uuid}/edge_health` **Direction:** publish (edge driver) → subscribe (backend, frontend) Periodic health status published by the edge driver (every \~5 seconds). The frontend uses these payloads to drive the live "green dot" online indicator on twin tiles, the workflow-pane Edge Devices tab, and the lab queue heuristics. The backend additionally bumps the corresponding `Edge.last_heartbeat` row (debounced to \~30 s per edge) so that the REST `Edge.is_online` flag agrees with the live MQTT signal. ```json theme={null} { "type": "edge_health", "timestamp": 1700000000.0, "twin_uuid": "twin-uuid-here", "edge_id": "edge-device-id", "uptime_seconds": 3600.0, "streams": { "front_camera": { "camera_id": "front_camera", "connection_state": "connected", "ice_connection_state": "connected", "frames_sent": 12345, "last_frame_ts": 1700000000.0, "fps": 29.97, "uptime_seconds": 3600.0, "restart_count": 0, "is_stale": false, "is_healthy": true } }, "stream_count": 1, "healthy_streams": 1 } ``` | Field | Type | Required | Description | | ----------------- | ------ | -------- | ------------------------------------------------- | | `type` | string | yes | Always `"edge_health"` | | `timestamp` | number | yes | Unix timestamp (seconds) | | `twin_uuid` | string | yes | Twin UUID | | `edge_id` | string | yes | Edge device identifier | | `uptime_seconds` | number | yes | Seconds since the driver started | | `streams` | object | no | Map of camera/stream IDs to stream health objects | | `stream_count` | number | no | Total number of streams | | `healthy_streams` | number | no | Number of healthy streams | *** ## Driver log ### `cyberwave/twin/{twin_uuid}/driverlog` **Direction:** publish (edge core / driver) → subscribe (backend) Structured log messages from edge drivers. Displayed in the platform UI. ```json theme={null} { "type": "driver_log", "message": "Camera initialised on /dev/video0", "level": "info", "container_name": "cyberwave-driver-so101", "source": "edge_core", "timestamp": 1700000000.0, "edge_core_version": "1.2.3", "sdk_version": "0.9.0", "driver_image": "ghcr.io/cyberwave-os/so101-driver:latest" } ``` | Field | Type | Required | Description | | ------------------- | ------ | -------- | ------------------------------------------------- | | `type` | string | yes | Always `"driver_log"` | | `message` | string | yes | Log message text | | `level` | string | yes | `"debug"` \| `"info"` \| `"warning"` \| `"error"` | | `container_name` | string | no | Docker container name | | `source` | string | no | Log source identifier | | `timestamp` | number | yes | Unix timestamp (seconds) | | `edge_core_version` | string | no | Edge Core version string | | `sdk_version` | string | no | SDK version string | | `driver_image` | string | no | Docker image that produced the log | *** ## WebRTC signalling These topics set up WebRTC video between the edge and Cyberwave's media service (SFU), which forwards the stream to browsers and SDK consumers. ### `cyberwave/twin/{twin_uuid}/webrtc-offer` **Direction:** publish (edge) → subscribe (backend / media-service) ```json theme={null} { "type": "offer", "sdp": "v=0\r\n...", "target": "backend", "sender": "edge", "color_track_id": "video-0", "depth_track_id": "video-1", "timestamp": 1700000000.0 } ``` ### `cyberwave/twin/{twin_uuid}/webrtc-answer` **Direction:** publish (backend / media-service) → subscribe (edge) ```json theme={null} { "type": "answer", "sdp": "v=0\r\n...", "target": "edge", "sender": "backend", "frontend_type": "rgb", "timestamp": 1700000000.0 } ``` ### `cyberwave/twin/{twin_uuid}/webrtc-candidate` **Direction:** bidirectional ICE candidate exchange during WebRTC negotiation. Payload is the raw ICE candidate object. *** ## Environment ### `cyberwave/environment/{environment_uuid}/{update_type}` **Direction:** publish (backend / edge) → subscribe (frontend, other services) Generic environment update channel. `update_type` is a free-form string (e.g. `"twin_added"`, `"twin_removed"`, `"sensor_binding"`, `"event"`). ```json theme={null} { "type": "twin_added", "data": { "twin_uuid": "twin-uuid-here" }, "timestamp": 1700000000.0, "source_type": "edit" } ``` | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------------- | | `type` | string | yes | Same as `update_type` in the topic | | `data` | object | yes | Update payload (structure depends on `type`) | | `timestamp` | number | yes | Unix timestamp (seconds) | | `source_type` | string | no | See [source types](#source-types) | #### Sensor binding update ```json theme={null} { "type": "sensor_binding", "bindings": { "sensor-uuid-1": "target-uuid-1", "sensor-uuid-2": "target-uuid-2" }, "timestamp": 1700000000.0 } ``` *** ## Health check ### `cyberwave/ping/{resource_uuid}/request` **Direction:** publish (any client) → subscribe (backend) Connectivity probe. The backend replies on the corresponding pong topic. ```json theme={null} { "type": "ping", "timestamp": 1700000000.0 } ``` ### `cyberwave/pong/{resource_uuid}/response` **Direction:** publish (backend) → subscribe (client) ```json theme={null} { "type": "pong", "timestamp": 1700000000.0 } ``` *** ## Workflow run status ### `cyberwave/workflow-run/{run_uuid}/status` **Direction:** publish (backend) → subscribe (SDK clients) Status updates for a running workflow execution. ```json theme={null} { "status": "running", "timestamp": 1700000000.0 } ``` | `status` | Description | | ------------- | ------------------------ | | `"pending"` | Queued, not yet started | | `"running"` | Currently executing | | `"completed"` | Finished successfully | | `"failed"` | Terminated with an error | | `"cancelled"` | Cancelled by the user | # API Overview Source: https://docs.cyberwave.com/api-reference/overview How to authenticate with the Cyberwave REST API and when to use REST or MQTT. ## Introduction Cyberwave provides two main APIs to interact with the platform, each designed for specific use cases and communication patterns. ## REST API The REST API is used for **non-real-time communication** with the Cyberwave platform. It follows standard HTTP methods and is ideal for: * Creating and managing digital twins * Configuring robot settings * Retrieving historical data * Managing user accounts and permissions * Performing administrative tasks ### Authentication All REST endpoints require an API key. Create one under [**Profile → Access**](https://cyberwave.com/profile) (see [API tokens](/feature-reference/api-tokens)), then pass the key in the `Authorization` header on every request. | Field | Value | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | Base URL | `https://api.cyberwave.com` | | Auth header | `Authorization: Bearer ` | | Accepted prefixes | `Bearer` and `Token` (case-insensitive) | | OpenAPI security scheme | `CustomTokenAuthentication` (API key, header) | | Recommended env var | `CYBERWAVE_API_KEY` | | Where to get a key | [`https://cyberwave.com/profile`](https://cyberwave.com/profile) → **Access**. See [API tokens](/feature-reference/api-tokens). | ```bash theme={null} export CYBERWAVE_API_KEY="cw_your_token_here" curl -X GET "https://api.cyberwave.com/api/v1/projects" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" ``` ```python theme={null} import os import requests headers = { "Authorization": f"Bearer {os.environ['CYBERWAVE_API_KEY']}", } r = requests.get("https://api.cyberwave.com/api/v1/projects", headers=headers) r.raise_for_status() print(r.json()) ``` ```javascript theme={null} const res = await fetch("https://api.cyberwave.com/api/v1/projects", { headers: { Authorization: `Bearer ${process.env.CYBERWAVE_API_KEY}`, }, }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); const data = await res.json(); ``` Treat the API key like a password. Never commit it to source control or paste it into client-side code that ships to browsers. Prefer environment variables and short-lived keys for production deployments. ## MQTT API The MQTT API is used for **real-time communication** with robots and telemetry data. This lightweight, publish-subscribe protocol is perfect for: * Live robot control and commands * Real-time telemetry streaming * Sensor data collection * Event notifications * Low-latency bidirectional communication ## Choosing the Right API | Use Case | Recommended API | | ----------------------------------- | --------------- | | Fetch robot configuration | REST | | Send real-time commands to robots | MQTT | | Query historical telemetry | REST | | Stream live sensor data | MQTT | | Manage user permissions | REST | | Receive instant event notifications | MQTT | ## Getting Started To start using the Cyberwave APIs, make sure you have: 1. A valid API key or authentication credentials 2. The appropriate SDK installed (optional but recommended) 3. Network access to the Cyberwave platform Browse every REST endpoint, request schema, and response shape. Connect to MQTT and start streaming real-time data. # AddMemberByEmailRequest Source: https://docs.cyberwave.com/api-reference/rest/AddMemberByEmailRequest # AddMemberByEmailRequest ## Properties | Name | Type | Description | Notes | | --------- | ------- | ----------- | ---------------------------------- | | **email** | **str** | | | | **role** | **str** | | \[optional] \[default to 'member'] | # AddMemberByEmailResponse Source: https://docs.cyberwave.com/api-reference/rest/AddMemberByEmailResponse # AddMemberByEmailResponse ## Properties | Name | Type | Description | Notes | | ---------------- | ------------------------------------------------------------------ | ----------- | ----------- | | **success** | **bool** | | | | **user\_exists** | **bool** | | | | **message** | **str** | | | | **user** | [**OrgMemberUserSchema**](/api-reference/rest/OrgMemberUserSchema) | | \[optional] | # AddMemberUserSchema Source: https://docs.cyberwave.com/api-reference/rest/AddMemberUserSchema # AddMemberUserSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | | | **username** | **str** | | | | **email** | **str** | | | | **first\_name** | **str** | | \[optional] \[default to ''] | | **last\_name** | **str** | | \[optional] \[default to ''] | | **full\_name** | **str** | | \[optional] \[default to ''] | | **profile\_picture** | **str** | | \[optional] | # AlertSchema Source: https://docs.cyberwave.com/api-reference/rest/AlertSchema # AlertSchema Schema for Alert response. ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **media** | **str** | | \[optional] | | **alert\_type** | **str** | | | | **severity** | **str** | | | | **status** | **str** | | | | **source\_type** | **str** | | | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **workflow\_uuid** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | | | **created\_by\_uuid** | **str** | | \[optional] | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **resolved\_at** | **datetime** | | \[optional] | | **last\_seen\_at** | **datetime** | Timestamp of the most recent edge publish that deduped against this alert. Acts as a pure-observability heartbeat — does not auto-resolve. `null` for legacy rows. | \[optional] | | **dedupe\_count** | **int** | Number of times this alert has been re-asserted by an edge publish while still active (deduped against this row). Drives the workbench's "Re-asserted N×" badge. | | | **metadata** | **Dict\[str, object]** | Free-form per-`alert_type` state. For `driver_starting` this carries `phase` plus `progress_percent` / `downloaded_bytes` / `total_bytes` / `downloaded_human` / `total_human` while a driver image is being pulled — see [Edge driver alerts](/feature-reference/edge/drivers/alerts#driver_starting-progress-metadata). | \[optional] | # AssetCatalogImportSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetCatalogImportSchema # AssetCatalogImportSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **registry\_id** | **str** | | | | **workspace\_slug** | **str** | | | | **source\_url** | **str** | | \[optional] | | **source\_token** | **str** | | \[optional] | # AssetCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetCreateSchema # AssetCreateSchema ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----------------------------------- | | **name** | **str** | | | | **description** | **str** | | | | **visibility** | **str** | | \[optional] \[default to 'private'] | | **workspace\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **registry\_id** | **str** | | \[optional] | | **universal\_schema** | **Dict\[str, object]** | | \[optional] | # AssetCreateWithURDFSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetCreateWithURDFSchema # AssetCreateWithURDFSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----------- | | **file\_url** | **str** | | | | **description** | **str** | | \[optional] | | **main\_file\_path** | **str** | | | | **force\_name** | **str** | | | | **subfolder** | **str** | | \[optional] | | **branch** | **str** | | \[optional] | # AssetGLBFromAttachmentSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetGLBFromAttachmentSchema # AssetGLBFromAttachmentSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **attachment\_uuid** | **str** | | | # AssetListSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetListSchema # AssetListSchema ## Properties | Name | Type | Description | Notes | | -------------------------- | ---------------------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **visibility** | **str** | | \[optional] | | **registry\_id** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **capabilities** | **Dict\[str, object]** | | \[optional] | | **thumbnail** | **str** | | \[optional] | | **urdf\_file** | **str** | | \[optional] | | **glb\_file** | **str** | | \[optional] | | **has\_universal\_schema** | **bool** | | \[optional] \[default to False] | # AssetSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetSchema # AssetSchema ## Properties | Name | Type | Description | Notes | | -------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **visibility** | **str** | | \[optional] | | **owner\_uuid** | **str** | | \[optional] | | **registry\_id** | **str** | | \[optional] | | **registry\_id\_alias** | **str** | stub: optional admin-managed short alias slug that also resolves the asset in API and SDK lookups. | \[optional] | | **glb\_file** | **str** | | \[optional] | | **urdf\_file** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **kinematics** | **Dict\[str, object]** | | \[optional] | | **capabilities** | **Dict\[str, object]** | | \[optional] | | **thumbnail** | **str** | | \[optional] | | **has\_universal\_schema** | **bool** | | \[optional] \[default to False] | | **universal\_schema** | **Dict\[str, object]** | | \[optional] | # AssetUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/AssetUpdateSchema # AssetUpdateSchema > stub: Admins can set `registry_id_alias` to define a short asset identifier such as `camera`. ## Properties | Name | Type | Description | Notes | | ----------------------- | ---------------------- | ------------------------------------------------------------------------------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **registry\_id** | **str** | | \[optional] | | **registry\_id\_alias** | **str** | Short alias slug resolved anywhere an asset identifier is accepted. Admin-only. | \[optional] | | **universal\_schema** | **Dict\[str, object]** | | \[optional] | # AttachmentCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/AttachmentCreateSchema # AttachmentCreateSchema ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------- | ----------- | ----------- | | **asset\_uuid** | **str** | | \[optional] | | **twin\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # AttachmentSchema Source: https://docs.cyberwave.com/api-reference/rest/AttachmentSchema # AttachmentSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **asset\_uuid** | **str** | | \[optional] | | **twin\_uuid** | **str** | | \[optional] | | **organization\_uuid** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **file\_url** | **str** | | \[optional] | # AvailableFeaturesSchema Source: https://docs.cyberwave.com/api-reference/rest/AvailableFeaturesSchema # AvailableFeaturesSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------------------------------------------------------------------------------ | ----------- | ----- | | **features** | [**List\[FeatureMetadataSchema\]**](/api-reference/rest/FeatureMetadataSchema) | | | # BulkJointStatesUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/BulkJointStatesUpdateSchema # BulkJointStatesUpdateSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ---------------------- | ----------- | ----- | | **joint\_states** | **Dict\[str, object]** | | | # BusinessEventCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/BusinessEventCreateSchema # BusinessEventCreateSchema ## Properties | Name | Type | Description | Notes | | ----------------------- | ---------------------- | ----------- | ----------- | | **environment\_uuid** | **str** | | | | **twin\_uuid** | **str** | | \[optional] | | **event\_type** | **str** | | | | **source** | **str** | | \[optional] | | **severity** | **str** | | \[optional] | | **data** | **Dict\[str, object]** | | \[optional] | | **tags** | **List\[str]** | | \[optional] | | **correlation\_id** | **str** | | \[optional] | | **parent\_event\_uuid** | **str** | | \[optional] | | **occurred\_at** | **datetime** | | \[optional] | # BusinessEventListResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/BusinessEventListResponseSchema # BusinessEventListResponseSchema ## Properties | Name | Type | Description | Notes | | ----------- | -------------------------------------------------------------------------- | ----------- | ----- | | **success** | **bool** | | | | **events** | [**List\[BusinessEventSchema\]**](/api-reference/rest/BusinessEventSchema) | | | # BusinessEventSchema Source: https://docs.cyberwave.com/api-reference/rest/BusinessEventSchema # BusinessEventSchema ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----------- | | **event\_id** | **str** | | | | **event\_type** | **str** | | | | **source** | **str** | | | | **severity** | **str** | | | | **timestamp\_ms** | **int** | | | | **data** | **Dict\[str, object]** | | | | **environment\_uuid** | **str** | | | | **twin\_uuid** | **str** | | \[optional] | | **twin\_name** | **str** | | \[optional] | | **tags** | **List\[str]** | | | | **correlation\_id** | **str** | | \[optional] | | **parent\_event\_id** | **str** | | \[optional] | # CameraConfigUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/CameraConfigUpdateSchema # CameraConfigUpdateSchema Schema for updating camera configuration. ## Properties | Name | Type | Description | Notes | | ---------------- | ------- | ----------- | ------------------------------- | | **camera\_id** | **str** | | \[optional] | | **source** | **str** | | \[optional] | | **fps** | **int** | | \[optional] \[default to 10] | | **resolution** | **str** | | \[optional] \[default to 'VGA'] | | **camera\_type** | **str** | | \[optional] \[default to 'cv2'] | # CatalogApi Source: https://docs.cyberwave.com/api-reference/rest/CatalogApi # cyberwave.rest.CatalogApi All URIs are relative to *[http://localhost](http://localhost)* | Method | HTTP request | Description | | ----------------------------------------------------------------------------------------- | ------------------------------------ | ------------ | | [**src\_app\_api\_catalog\_seed\_seed\_catalog**](#src_app_api_catalog_seed_seed_catalog) | **POST** /api/v1/catalog/seed | Seed Catalog | | [**src\_app\_api\_catalog\_seed\_seed\_options**](#src_app_api_catalog_seed_seed_options) | **GET** /api/v1/catalog/seed-options | Seed Options | # **src\_app\_api\_catalog\_seed\_seed\_catalog** > CatalogSeedResponseSchema src\_app\_api\_catalog\_seed\_seed\_catalog(catalog\_seed\_request\_schema) Seed Catalog ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.catalog_seed_request_schema import CatalogSeedRequestSchema from cyberwave.rest.models.catalog_seed_response_schema import CatalogSeedResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CatalogApi(api_client) catalog_seed_request_schema = cyberwave.rest.CatalogSeedRequestSchema() # CatalogSeedRequestSchema | try: # Seed Catalog api_response = api_instance.src_app_api_catalog_seed_seed_catalog(catalog_seed_request_schema) print("The response of CatalogApi->src_app_api_catalog_seed_seed_catalog:\n") pprint(api_response) except Exception as e: print("Exception when calling CatalogApi->src_app_api_catalog_seed_seed_catalog: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **catalog\_seed\_request\_schema** | [**CatalogSeedRequestSchema**](/api-reference/rest/CatalogSeedRequestSchema) | | | ### Return type [**CatalogSeedResponseSchema**](/api-reference/rest/CatalogSeedResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_catalog\_seed\_seed\_options** > CatalogSeedOptionsResponseSchema src\_app\_api\_catalog\_seed\_seed\_options() Seed Options ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.catalog_seed_options_response_schema import CatalogSeedOptionsResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CatalogApi(api_client) try: # Seed Options api_response = api_instance.src_app_api_catalog_seed_seed_options() print("The response of CatalogApi->src_app_api_catalog_seed_seed_options:\n") pprint(api_response) except Exception as e: print("Exception when calling CatalogApi->src_app_api_catalog_seed_seed_options: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**CatalogSeedOptionsResponseSchema**](/api-reference/rest/CatalogSeedOptionsResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # CatalogSeedGroupSchema Source: https://docs.cyberwave.com/api-reference/rest/CatalogSeedGroupSchema # CatalogSeedGroupSchema ## Properties | Name | Type | Description | Notes | | ----------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **created** | **int** | | | | **skipped** | **int** | | | | **errors** | **int** | | | | **items** | [**List\[CatalogSeedItemSchema\]**](/api-reference/rest/CatalogSeedItemSchema) | | | # CatalogSeedItemSchema Source: https://docs.cyberwave.com/api-reference/rest/CatalogSeedItemSchema # CatalogSeedItemSchema ## Properties | Name | Type | Description | Notes | | ----------- | ------- | ----------- | ----------- | | **key** | **str** | | | | **name** | **str** | | | | **status** | **str** | | | | **message** | **str** | | \[optional] | # CatalogSeedOptionSchema Source: https://docs.cyberwave.com/api-reference/rest/CatalogSeedOptionSchema # CatalogSeedOptionSchema ## Properties | Name | Type | Description | Notes | | ------------------------- | ------- | ----------- | ----------- | | **key** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **controller\_type** | **str** | | \[optional] | | **model\_provider\_name** | **str** | | \[optional] | # CatalogSeedOptionsResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/CatalogSeedOptionsResponseSchema # CatalogSeedOptionsResponseSchema ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------------------------------------------------------------------- | ----------- | ----- | | **controllers** | [**List\[CatalogSeedOptionSchema\]**](/api-reference/rest/CatalogSeedOptionSchema) | | | | **mlmodels** | [**List\[CatalogSeedOptionSchema\]**](/api-reference/rest/CatalogSeedOptionSchema) | | | # CatalogSeedRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/CatalogSeedRequestSchema # CatalogSeedRequestSchema ## Properties | Name | Type | Description | Notes | | ------------------------------ | -------------- | ----------- | ------------------------------ | | **workspace\_uuid** | **str** | | \[optional] | | **seed\_controller\_policies** | **bool** | | \[optional] \[default to True] | | **seed\_mlmodels** | **bool** | | \[optional] \[default to True] | | **controller\_keys** | **List\[str]** | | \[optional] | | **mlmodel\_keys** | **List\[str]** | | \[optional] | # CatalogSeedResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/CatalogSeedResponseSchema # CatalogSeedResponseSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ------------------------------------------------------------------------ | ----------- | ----- | | **workspace\_uuid** | **str** | | | | **controllers** | [**CatalogSeedGroupSchema**](/api-reference/rest/CatalogSeedGroupSchema) | | | | **mlmodels** | [**CatalogSeedGroupSchema**](/api-reference/rest/CatalogSeedGroupSchema) | | | # CloudNodeApi Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeApi # cyberwave.rest.CloudNodeApi All URIs are relative to *[http://localhost](http://localhost)* | Method | HTTP request | Description | | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ---------------------------- | | [**src\_app\_api\_cloud\_nodes\_create\_instance**](#src_app_api_cloud_nodes_create_instance) | **POST** /api/v1/cloud-node | Create Instance | | [**src\_app\_api\_cloud\_nodes\_get\_instance\_logs**](#src_app_api_cloud_nodes_get_instance_logs) | **GET** `/api/v1/cloud-node/instances/{instance_uuid}/logs` | Get Instance Logs | | [**src\_app\_api\_cloud\_nodes\_get\_instance\_metadata**](#src_app_api_cloud_nodes_get_instance_metadata) | **GET** `/api/v1/cloud-node/instances/{instance_uuid}/metadata` | Get Instance Metadata | | [**src\_app\_api\_cloud\_nodes\_get\_instance\_status**](#src_app_api_cloud_nodes_get_instance_status) | **GET** `/api/v1/cloud-node/instances/{instance_uuid}/status` | Get Instance Status | | [**src\_app\_api\_cloud\_nodes\_list\_instances**](#src_app_api_cloud_nodes_list_instances) | **GET** /api/v1/cloud-node/instances | List Instances | | [**src\_app\_api\_cloud\_nodes\_mark\_instance\_failed**](#src_app_api_cloud_nodes_mark_instance_failed) | **POST** `/api/v1/cloud-node/{uuid}/failed` | Mark Instance Failed | | [**src\_app\_api\_cloud\_nodes\_mark\_instance\_terminated**](#src_app_api_cloud_nodes_mark_instance_terminated) | **POST** `/api/v1/cloud-node/{uuid}/terminated` | Mark Instance Terminated | | [**src\_app\_api\_cloud\_nodes\_record\_heartbeat**](#src_app_api_cloud_nodes_record_heartbeat) | **POST** `/api/v1/cloud-node/{uuid}/heartbeat` | Record Heartbeat | | [**src\_app\_api\_cloud\_nodes\_register\_gpu\_instance**](#src_app_api_cloud_nodes_register_gpu_instance) | **POST** `/api/v1/cloud-node/{uuid}/register` | Register Gpu Instance | | [**src\_app\_api\_cloud\_nodes\_save\_cloud\_node\_instance\_log**](#src_app_api_cloud_nodes_save_cloud_node_instance_log) | **POST** `/api/v1/cloud-node/{uuid}/log` | Save Cloud Node Instance Log | # **src\_app\_api\_cloud\_nodes\_create\_instance** > CloudNodeInstanceSchema src\_app\_api\_cloud\_nodes\_create\_instance(cloud\_node\_instance\_create\_request) Create Instance Create a new Cloud Node instance. The backend is the owner of the UUID and slug: * If slug is provided, it must be unique within the workspace * If slug is not provided, an auto-generated slug will be created ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_instance_create_request import CloudNodeInstanceCreateRequest from cyberwave.rest.models.cloud_node_instance_schema import CloudNodeInstanceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) cloud_node_instance_create_request = cyberwave.rest.CloudNodeInstanceCreateRequest() # CloudNodeInstanceCreateRequest | try: # Create Instance api_response = api_instance.src_app_api_cloud_nodes_create_instance(cloud_node_instance_create_request) print("The response of CloudNodeApi->src_app_api_cloud_nodes_create_instance:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_create_instance: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------------ | ---------------------------------------------------------------------------------------- | ----------- | ----- | | **cloud\_node\_instance\_create\_request** | [**CloudNodeInstanceCreateRequest**](/api-reference/rest/CloudNodeInstanceCreateRequest) | | | ### Return type [**CloudNodeInstanceSchema**](/api-reference/rest/CloudNodeInstanceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_get\_instance\_logs** > CloudNodeInstanceLogsResponse src\_app\_api\_cloud\_nodes\_get\_instance\_logs(instance\_uuid, log\_type=log\_type, limit=limit) Get Instance Logs Retrieve logs for a Cloud Node (GPU) instance. Returns log metadata and the combined content of the most recent log entries, limited to the last N lines (default 100). Args: instance\_uuid: UUID of the Cloud Node instance log\_type: Optional filter by log type ("stdout", "stderr", "system", "app") limit: Maximum number of lines to return (default 100, max 1000) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_instance_logs_response import CloudNodeInstanceLogsResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) instance_uuid = 'instance_uuid_example' # str | log_type = 'log_type_example' # str | (optional) limit = 100 # int | (optional) (default to 100) try: # Get Instance Logs api_response = api_instance.src_app_api_cloud_nodes_get_instance_logs(instance_uuid, log_type=log_type, limit=limit) print("The response of CloudNodeApi->src_app_api_cloud_nodes_get_instance_logs:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_get_instance_logs: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----------------------------- | | **instance\_uuid** | **str** | | | | **log\_type** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**CloudNodeInstanceLogsResponse**](/api-reference/rest/CloudNodeInstanceLogsResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_get\_instance\_metadata** > Dict\[str, object] src\_app\_api\_cloud\_nodes\_get\_instance\_metadata(instance\_uuid) Get Instance Metadata Get the metadata for a Cloud Node instance. Used by Cloud Node services to self-configure at startup by fetching their instance-specific configuration (weights URLs, twin UUIDs, etc.) without needing every field passed as environment variables. Authentication: Requires CYBERWAVE\_API\_KEY (admin token or instance-specific token) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) instance_uuid = 'instance_uuid_example' # str | try: # Get Instance Metadata api_response = api_instance.src_app_api_cloud_nodes_get_instance_metadata(instance_uuid) print("The response of CloudNodeApi->src_app_api_cloud_nodes_get_instance_metadata:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_get_instance_metadata: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **instance\_uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_get\_instance\_status** > CloudNodeInstanceStatusResponse src\_app\_api\_cloud\_nodes\_get\_instance\_status(instance\_uuid) Get Instance Status Get the current status of a Cloud Node (GPU) instance. Used by Cloud Node (GPU) services to check their registration status and by monitoring systems to verify instance health. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_instance_status_response import CloudNodeInstanceStatusResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) instance_uuid = 'instance_uuid_example' # str | try: # Get Instance Status api_response = api_instance.src_app_api_cloud_nodes_get_instance_status(instance_uuid) print("The response of CloudNodeApi->src_app_api_cloud_nodes_get_instance_status:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_get_instance_status: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **instance\_uuid** | **str** | | | ### Return type [**CloudNodeInstanceStatusResponse**](/api-reference/rest/CloudNodeInstanceStatusResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_list\_instances** > List\[CloudNodeInstanceSchema] src\_app\_api\_cloud\_nodes\_list\_instances(profile\_slug=profile\_slug, status=status, workspace\_slug=workspace\_slug) List Instances List Cloud Node instances for a workspace. Optionally filter by profile\_slug or status. If workspace\_slug is provided, uses that workspace; otherwise uses the user's default. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_instance_schema import CloudNodeInstanceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) profile_slug = 'profile_slug_example' # str | (optional) status = 'status_example' # str | (optional) workspace_slug = 'workspace_slug_example' # str | (optional) try: # List Instances api_response = api_instance.src_app_api_cloud_nodes_list_instances(profile_slug=profile_slug, status=status, workspace_slug=workspace_slug) print("The response of CloudNodeApi->src_app_api_cloud_nodes_list_instances:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_list_instances: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **profile\_slug** | **str** | | \[optional] | | **status** | **str** | | \[optional] | | **workspace\_slug** | **str** | | \[optional] | ### Return type [**List\[CloudNodeInstanceSchema\]**](/api-reference/rest/CloudNodeInstanceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_mark\_instance\_failed** > CloudNodeFailedResponse src\_app\_api\_cloud\_nodes\_mark\_instance\_failed(uuid, cloud\_node\_failed\_request) Mark Instance Failed Mark a Cloud Node (GPU) instance as failed. Called by the GitHub Actions workflow when provisioning fails or the instance crashes unexpectedly. Any associated workloads will be re-queued. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_failed_request import CloudNodeFailedRequest from cyberwave.rest.models.cloud_node_failed_response import CloudNodeFailedResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) uuid = 'uuid_example' # str | cloud_node_failed_request = cyberwave.rest.CloudNodeFailedRequest() # CloudNodeFailedRequest | try: # Mark Instance Failed api_response = api_instance.src_app_api_cloud_nodes_mark_instance_failed(uuid, cloud_node_failed_request) print("The response of CloudNodeApi->src_app_api_cloud_nodes_mark_instance_failed:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_mark_instance_failed: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_failed\_request** | [**CloudNodeFailedRequest**](/api-reference/rest/CloudNodeFailedRequest) | | | ### Return type [**CloudNodeFailedResponse**](/api-reference/rest/CloudNodeFailedResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_mark\_instance\_terminated** > CloudNodeTerminatedResponse src\_app\_api\_cloud\_nodes\_mark\_instance\_terminated(uuid, cloud\_node\_terminated\_request) Mark Instance Terminated Mark a Cloud Node (GPU) instance as terminated. Called by the package (cyberwave-cloud-node) once a termination is triggered OR by the GitHub Actions workflow after Terraform has successfully (when used by us) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_terminated_request import CloudNodeTerminatedRequest from cyberwave.rest.models.cloud_node_terminated_response import CloudNodeTerminatedResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) uuid = 'uuid_example' # str | cloud_node_terminated_request = cyberwave.rest.CloudNodeTerminatedRequest() # CloudNodeTerminatedRequest | try: # Mark Instance Terminated api_response = api_instance.src_app_api_cloud_nodes_mark_instance_terminated(uuid, cloud_node_terminated_request) print("The response of CloudNodeApi->src_app_api_cloud_nodes_mark_instance_terminated:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_mark_instance_terminated: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------ | -------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_terminated\_request** | [**CloudNodeTerminatedRequest**](/api-reference/rest/CloudNodeTerminatedRequest) | | | ### Return type [**CloudNodeTerminatedResponse**](/api-reference/rest/CloudNodeTerminatedResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_record\_heartbeat** > CloudeNodeHeartbeatResponse src\_app\_api\_cloud\_nodes\_record\_heartbeat(uuid) Record Heartbeat Record a heartbeat from a Cloud Node (GPU) instance. Called periodically by the Cloud Node (GPU) service to signal it is alive and healthy. Missing heartbeats will cause the instance to be marked as stale and terminated. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloude_node_heartbeat_response import CloudeNodeHeartbeatResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) uuid = 'uuid_example' # str | try: # Record Heartbeat api_response = api_instance.src_app_api_cloud_nodes_record_heartbeat(uuid) print("The response of CloudNodeApi->src_app_api_cloud_nodes_record_heartbeat:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_record_heartbeat: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**CloudeNodeHeartbeatResponse**](/api-reference/rest/CloudeNodeHeartbeatResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_register\_gpu\_instance** > CloudeNodeInstanceRegisterResponse src\_app\_api\_cloud\_nodes\_register\_gpu\_instance(uuid, cloud\_node\_instance\_register\_request) Register Gpu Instance Register a Cloud Node (GPU) instance after it has booted and is ready to serve. Called by the Cloud Node (GPU) service once its dependencies (e.g. CUDA, etc) are available and the service is listening. This endpoint only registers an existing instance. The instance must have been created via the create endpoint first. The profile\_slug can be updated during registration to reflect the actual running profile. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_instance_register_request import CloudNodeInstanceRegisterRequest from cyberwave.rest.models.cloude_node_instance_register_response import CloudeNodeInstanceRegisterResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) uuid = 'uuid_example' # str | cloud_node_instance_register_request = cyberwave.rest.CloudNodeInstanceRegisterRequest() # CloudNodeInstanceRegisterRequest | try: # Register Gpu Instance api_response = api_instance.src_app_api_cloud_nodes_register_gpu_instance(uuid, cloud_node_instance_register_request) print("The response of CloudNodeApi->src_app_api_cloud_nodes_register_gpu_instance:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_register_gpu_instance: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------------------- | -------------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_instance\_register\_request** | [**CloudNodeInstanceRegisterRequest**](/api-reference/rest/CloudNodeInstanceRegisterRequest) | | | ### Return type [**CloudeNodeInstanceRegisterResponse**](/api-reference/rest/CloudeNodeInstanceRegisterResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_nodes\_save\_cloud\_node\_instance\_log** > CloudNodeLogResponse src\_app\_api\_cloud\_nodes\_save\_cloud\_node\_instance\_log(uuid, cloud\_node\_log\_request) Save Cloud Node Instance Log Save a log entry for a Cloud Node (GPU) instance. Logs are stored asynchronously in GCS with metadata in the database. This allows Cloud Node instances to stream logs without blocking. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_log_request import CloudNodeLogRequest from cyberwave.rest.models.cloud_node_log_response import CloudNodeLogResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeApi(api_client) uuid = 'uuid_example' # str | cloud_node_log_request = cyberwave.rest.CloudNodeLogRequest() # CloudNodeLogRequest | try: # Save Cloud Node Instance Log api_response = api_instance.src_app_api_cloud_nodes_save_cloud_node_instance_log(uuid, cloud_node_log_request) print("The response of CloudNodeApi->src_app_api_cloud_nodes_save_cloud_node_instance_log:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeApi->src_app_api_cloud_nodes_save_cloud_node_instance_log: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_log\_request** | [**CloudNodeLogRequest**](/api-reference/rest/CloudNodeLogRequest) | | | ### Return type [**CloudNodeLogResponse**](/api-reference/rest/CloudNodeLogResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # CloudNodeFailedRequest Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeFailedRequest # CloudNodeFailedRequest ## Properties | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **slug** | **str** | | \[optional] | | **workspace\_slug** | **str** | | \[optional] | | **instance\_uuid** | **str** | | \[optional] | | **error** | **str** | | | # CloudNodeFailedResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeFailedResponse # CloudNodeFailedResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | # CloudNodeInstanceCreateRequest Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeInstanceCreateRequest # CloudNodeInstanceCreateRequest ## Properties | Name | Type | Description | Notes | | ------------------- | ------------------------------------------------ | ----------- | --------------------------------------- | | **profile\_slug** | **str** | | | | **slug** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **provider** | **str** | | \[optional] \[default to 'self-hosted'] | | **visibility** | [**Visibility**](/api-reference/rest/Visibility) | | \[optional] | # CloudNodeInstanceLogsResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeInstanceLogsResponse # CloudNodeInstanceLogsResponse ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------------------------------------------------------------------- | ----------- | ----- | | **instance\_uuid** | **str** | | | | **logs** | [**List\[CloudNodeLogEntrySchema\]**](/api-reference/rest/CloudNodeLogEntrySchema) | | | | **content** | **str** | | | # CloudNodeInstanceRegisterRequest Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeInstanceRegisterRequest # CloudNodeInstanceRegisterRequest ## Properties | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **profile\_slug** | **str** | | | # CloudNodeInstanceSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeInstanceSchema # CloudNodeInstanceSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **slug** | **str** | | | | **status** | **str** | | | | **profile\_slug** | **str** | | | # CloudNodeInstanceStatusResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeInstanceStatusResponse # CloudNodeInstanceStatusResponse ## Properties | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **slug** | **str** | | \[optional] | | **workspace\_slug** | **str** | | \[optional] | | **instance\_uuid** | **str** | | \[optional] | | **status** | **str** | | | # CloudNodeLogEntrySchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeLogEntrySchema # CloudNodeLogEntrySchema ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **log\_type** | **str** | | | | **start\_time** | **str** | | | | **size\_bytes** | **int** | | | | **line\_count** | **int** | | | | **gcs\_path** | **str** | | | # CloudNodeLogRequest Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeLogRequest # CloudNodeLogRequest ## Properties | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ---------------------------------- | | **slug** | **str** | | \[optional] | | **workspace\_slug** | **str** | | \[optional] | | **instance\_uuid** | **str** | | \[optional] | | **log\_type** | **str** | | \[optional] \[default to 'stdout'] | | **log\_content** | **str** | | | # CloudNodeLogResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeLogResponse # CloudNodeLogResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | # CloudNodeTerminatedRequest Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeTerminatedRequest # CloudNodeTerminatedRequest ## Properties | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **slug** | **str** | | \[optional] | | **workspace\_slug** | **str** | | \[optional] | | **instance\_uuid** | **str** | | \[optional] | # CloudNodeTerminatedResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeTerminatedResponse # CloudNodeTerminatedResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | # CloudNodeWorkloadAssignSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadAssignSchema # CloudNodeWorkloadAssignSchema Request schema for assigning a workload to an instance. ## Properties | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **instance\_uuid** | **str** | | | # CloudNodeWorkloadAttachmentResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadAttachmentResponseSchema # CloudNodeWorkloadAttachmentResponseSchema Response schema for a Cloud Node workload attachment. ## Properties | Name | Type | Description | Notes | | --------------------- | ------- | ----------- | ----- | | **signed\_url** | **str** | | | | **filename** | **str** | | | | **expiration\_hours** | **int** | | | # CloudNodeWorkloadAttachmentSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadAttachmentSchema # CloudNodeWorkloadAttachmentSchema Request schema for a Cloud Node workload attachment. ## Properties | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **filename** | **str** | | | # CloudNodeWorkloadCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadCreateSchema # CloudNodeWorkloadCreateSchema Request schema for creating a Cloud Node workload. ## Properties | Name | Type | Description | Notes | | -------------------- | ---------------------- | ----------- | ----------- | | **profile\_slug** | **str** | | | | **workspace\_uuid** | **str** | | \[optional] | | **instance\_uuid** | **str** | | \[optional] | | **command\_type** | **str** | | \[optional] | | **command\_params** | **Dict\[str, object]** | | \[optional] | | **callback\_task** | **str** | | \[optional] | | **callback\_kwargs** | **Dict\[str, object]** | | \[optional] | # CloudNodeWorkloadResultSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadResultSchema # CloudNodeWorkloadResultSchema Response schema for a Cloud Node workload result. This endpoint is called by the Cloud Node after the file upload is completed. ## Properties | Name | Type | Description | Notes | | --------------------- | -------------- | ----------- | ----- | | **filenames** | **List\[str]** | | | | **signed\_urls** | **List\[str]** | | | | **attachment\_uuids** | **List\[str]** | | | # CloudNodeWorkloadSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadSchema # CloudNodeWorkloadSchema Response schema for a Cloud Node workload. ## Properties | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **profile\_uuid** | **str** | | | | **profile\_slug** | **str** | | | | **instance\_uuid** | **str** | | | | **instance\_slug** | **str** | | | | **status** | **str** | | | | **workspace\_uuid** | **str** | | | | **visibility** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by\_email** | **str** | | | | **command\_type** | **str** | | | | **command\_params** | **Dict\[str, object]** | | | | **callback\_task** | **str** | | | | **callback\_kwargs** | **Dict\[str, object]** | | | # CloudNodeWorkloadUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadUpdateSchema # CloudNodeWorkloadUpdateSchema Request schema for updating a Cloud Node workload. ## Properties | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----------- | | **status** | **str** | | \[optional] | | **instance\_uuid** | **str** | | \[optional] | # CloudNodeWorkloadsApi Source: https://docs.cyberwave.com/api-reference/rest/CloudNodeWorkloadsApi # cyberwave.rest.CloudNodeWorkloadsApi All URIs are relative to *[http://localhost](http://localhost)* | Method | HTTP request | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------ | | [**src\_app\_api\_cloud\_node\_workloads\_assign\_workload\_to\_instance**](#src_app_api_cloud_node_workloads_assign_workload_to_instance) | **POST** `/api/v1/cloud-node-workloads/{uuid}/assign` | Assign Workload To Instance | | [**src\_app\_api\_cloud\_node\_workloads\_create\_workload**](#src_app_api_cloud_node_workloads_create_workload) | **POST** /api/v1/cloud-node-workloads | Create Workload | | [**src\_app\_api\_cloud\_node\_workloads\_delete\_workload**](#src_app_api_cloud_node_workloads_delete_workload) | **DELETE** `/api/v1/cloud-node-workloads/{uuid}` | Delete Workload | | [**src\_app\_api\_cloud\_node\_workloads\_get\_signed\_url\_for\_attachment\_upload**](#src_app_api_cloud_node_workloads_get_signed_url_for_attachment_upload) | **POST** `/api/v1/cloud-node-workloads/{uuid}/attachments` | Get Signed Url For Attachment Upload | | [**src\_app\_api\_cloud\_node\_workloads\_get\_workload**](#src_app_api_cloud_node_workloads_get_workload) | **GET** `/api/v1/cloud-node-workloads/{uuid}` | Get Workload | | [**src\_app\_api\_cloud\_node\_workloads\_get\_workload\_execution**](#src_app_api_cloud_node_workloads_get_workload_execution) | **POST** `/api/v1/cloud-node-workloads/{uuid}/execution` | Get Workload Execution | | [**src\_app\_api\_cloud\_node\_workloads\_list\_pending\_workloads**](#src_app_api_cloud_node_workloads_list_pending_workloads) | **GET** /api/v1/cloud-node-workloads/pending | List Pending Workloads | | [**src\_app\_api\_cloud\_node\_workloads\_list\_task\_executions**](#src_app_api_cloud_node_workloads_list_task_executions) | **GET** /api/v1/cloud-node-workloads/executions | List Task Executions | | [**src\_app\_api\_cloud\_node\_workloads\_list\_workloads**](#src_app_api_cloud_node_workloads_list_workloads) | **GET** /api/v1/cloud-node-workloads | List Workloads | | [**src\_app\_api\_cloud\_node\_workloads\_mark\_workload\_completed**](#src_app_api_cloud_node_workloads_mark_workload_completed) | **POST** `/api/v1/cloud-node-workloads/{uuid}/complete` | Mark Workload Completed | | [**src\_app\_api\_cloud\_node\_workloads\_mark\_workload\_failed**](#src_app_api_cloud_node_workloads_mark_workload_failed) | **POST** `/api/v1/cloud-node-workloads/{uuid}/fail` | Mark Workload Failed | | [**src\_app\_api\_cloud\_node\_workloads\_update\_workload**](#src_app_api_cloud_node_workloads_update_workload) | **PUT** `/api/v1/cloud-node-workloads/{uuid}` | Update Workload | | [**src\_app\_api\_cloud\_node\_workloads\_workload\_upload\_results**](#src_app_api_cloud_node_workloads_workload_upload_results) | **POST** `/api/v1/cloud-node-workloads/{uuid}/upload-results` | Workload Upload Results | # **src\_app\_api\_cloud\_node\_workloads\_assign\_workload\_to\_instance** > CloudNodeWorkloadSchema src\_app\_api\_cloud\_node\_workloads\_assign\_workload\_to\_instance(uuid, cloud\_node\_workload\_assign\_schema) Assign Workload To Instance Assign a workload to a Cloud Node instance. This also updates the workload status to ASSIGNED. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_assign_schema import CloudNodeWorkloadAssignSchema from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | cloud_node_workload_assign_schema = cyberwave.rest.CloudNodeWorkloadAssignSchema() # CloudNodeWorkloadAssignSchema | try: # Assign Workload To Instance api_response = api_instance.src_app_api_cloud_node_workloads_assign_workload_to_instance(uuid, cloud_node_workload_assign_schema) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_assign_workload_to_instance:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_assign_workload_to_instance: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_workload\_assign\_schema** | [**CloudNodeWorkloadAssignSchema**](/api-reference/rest/CloudNodeWorkloadAssignSchema) | | | ### Return type [**CloudNodeWorkloadSchema**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_create\_workload** > CloudNodeWorkloadSchema src\_app\_api\_cloud\_node\_workloads\_create\_workload(cloud\_node\_workload\_create\_schema) Create Workload Create a new Cloud Node workload. The workload will be created in PENDING status and can later be assigned to an available Cloud Node instance. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_create_schema import CloudNodeWorkloadCreateSchema from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) cloud_node_workload_create_schema = cyberwave.rest.CloudNodeWorkloadCreateSchema() # CloudNodeWorkloadCreateSchema | try: # Create Workload api_response = api_instance.src_app_api_cloud_node_workloads_create_workload(cloud_node_workload_create_schema) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_create_workload:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_create_workload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **cloud\_node\_workload\_create\_schema** | [**CloudNodeWorkloadCreateSchema**](/api-reference/rest/CloudNodeWorkloadCreateSchema) | | | ### Return type [**CloudNodeWorkloadSchema**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_delete\_workload** > src\_app\_api\_cloud\_node\_workloads\_delete\_workload(uuid) Delete Workload Delete a Cloud Node workload. Only pending or completed workloads can be deleted. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | try: # Delete Workload api_instance.src_app_api_cloud_node_workloads_delete_workload(uuid) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_delete_workload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_get\_signed\_url\_for\_attachment\_upload** > CloudNodeWorkloadAttachmentResponseSchema src\_app\_api\_cloud\_node\_workloads\_get\_signed\_url\_for\_attachment\_upload(uuid, cloud\_node\_workload\_attachment\_schema) Get Signed Url For Attachment Upload Generate a signed URL for uploading an attachment to a Cloud Node workload. Returns a signed URL that can be used to upload a file directly to Google Cloud Storage. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_attachment_response_schema import CloudNodeWorkloadAttachmentResponseSchema from cyberwave.rest.models.cloud_node_workload_attachment_schema import CloudNodeWorkloadAttachmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | cloud_node_workload_attachment_schema = cyberwave.rest.CloudNodeWorkloadAttachmentSchema() # CloudNodeWorkloadAttachmentSchema | try: # Get Signed Url For Attachment Upload api_response = api_instance.src_app_api_cloud_node_workloads_get_signed_url_for_attachment_upload(uuid, cloud_node_workload_attachment_schema) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_get_signed_url_for_attachment_upload:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_get_signed_url_for_attachment_upload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_workload\_attachment\_schema** | [**CloudNodeWorkloadAttachmentSchema**](/api-reference/rest/CloudNodeWorkloadAttachmentSchema) | | | ### Return type [**CloudNodeWorkloadAttachmentResponseSchema**](/api-reference/rest/CloudNodeWorkloadAttachmentResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_get\_workload** > CloudNodeWorkloadSchema src\_app\_api\_cloud\_node\_workloads\_get\_workload(uuid) Get Workload Get a specific Cloud Node workload by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | try: # Get Workload api_response = api_instance.src_app_api_cloud_node_workloads_get_workload(uuid) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_get_workload:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_get_workload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**CloudNodeWorkloadSchema**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_get\_workload\_execution** > DeferredTaskExecutionResponseSchema src\_app\_api\_cloud\_node\_workloads\_get\_workload\_execution(uuid) Get Workload Execution Get the execution information of a Cloud Node workload. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.deferred_task_execution_response_schema import DeferredTaskExecutionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | try: # Get Workload Execution api_response = api_instance.src_app_api_cloud_node_workloads_get_workload_execution(uuid) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_get_workload_execution:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_get_workload_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**DeferredTaskExecutionResponseSchema**](/api-reference/rest/DeferredTaskExecutionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_list\_pending\_workloads** > List\[CloudNodeWorkloadSchema] src\_app\_api\_cloud\_node\_workloads\_list\_pending\_workloads() List Pending Workloads List all pending Cloud Node workloads visible to the authenticated user. Useful for finding workloads that need to be assigned to instances. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) try: # List Pending Workloads api_response = api_instance.src_app_api_cloud_node_workloads_list_pending_workloads() print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_list_pending_workloads:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_list_pending_workloads: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[CloudNodeWorkloadSchema\]**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_list\_task\_executions** > List\[DeferredTaskExecutionResponseSchema] src\_app\_api\_cloud\_node\_workloads\_list\_task\_executions(workspace\_uuid) List Task Executions List all executions for a workspace. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.deferred_task_execution_response_schema import DeferredTaskExecutionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) workspace_uuid = 'workspace_uuid_example' # str | try: # List Task Executions api_response = api_instance.src_app_api_cloud_node_workloads_list_task_executions(workspace_uuid) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_list_task_executions:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_list_task_executions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **workspace\_uuid** | **str** | | | ### Return type [**List\[DeferredTaskExecutionResponseSchema\]**](/api-reference/rest/DeferredTaskExecutionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_list\_workloads** > List\[CloudNodeWorkloadSchema] src\_app\_api\_cloud\_node\_workloads\_list\_workloads(status=status, profile\_slug=profile\_slug, workspace\_uuid=workspace\_uuid) List Workloads List all Cloud Node workloads visible to the authenticated user. Optionally filter by status, profile\_slug, or workspace\_uuid. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) status = 'status_example' # str | (optional) profile_slug = 'profile_slug_example' # str | (optional) workspace_uuid = 'workspace_uuid_example' # str | (optional) try: # List Workloads api_response = api_instance.src_app_api_cloud_node_workloads_list_workloads(status=status, profile_slug=profile_slug, workspace_uuid=workspace_uuid) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_list_workloads:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_list_workloads: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **status** | **str** | | \[optional] | | **profile\_slug** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | ### Return type [**List\[CloudNodeWorkloadSchema\]**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_mark\_workload\_completed** > CloudNodeWorkloadSchema src\_app\_api\_cloud\_node\_workloads\_mark\_workload\_completed(uuid) Mark Workload Completed Mark a workload as completed. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | try: # Mark Workload Completed api_response = api_instance.src_app_api_cloud_node_workloads_mark_workload_completed(uuid) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_mark_workload_completed:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_mark_workload_completed: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**CloudNodeWorkloadSchema**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_mark\_workload\_failed** > CloudNodeWorkloadSchema src\_app\_api\_cloud\_node\_workloads\_mark\_workload\_failed(uuid) Mark Workload Failed Mark a workload as failed. This can be used when a workload encounters an error during execution. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | try: # Mark Workload Failed api_response = api_instance.src_app_api_cloud_node_workloads_mark_workload_failed(uuid) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_mark_workload_failed:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_mark_workload_failed: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**CloudNodeWorkloadSchema**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_update\_workload** > CloudNodeWorkloadSchema src\_app\_api\_cloud\_node\_workloads\_update\_workload(uuid, cloud\_node\_workload\_update\_schema) Update Workload Update a Cloud Node workload. Can be used to update status or assign/unassign an instance. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_schema import CloudNodeWorkloadSchema from cyberwave.rest.models.cloud_node_workload_update_schema import CloudNodeWorkloadUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | cloud_node_workload_update_schema = cyberwave.rest.CloudNodeWorkloadUpdateSchema() # CloudNodeWorkloadUpdateSchema | try: # Update Workload api_response = api_instance.src_app_api_cloud_node_workloads_update_workload(uuid, cloud_node_workload_update_schema) print("The response of CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_update_workload:\n") pprint(api_response) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_update_workload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_workload\_update\_schema** | [**CloudNodeWorkloadUpdateSchema**](/api-reference/rest/CloudNodeWorkloadUpdateSchema) | | | ### Return type [**CloudNodeWorkloadSchema**](/api-reference/rest/CloudNodeWorkloadSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_cloud\_node\_workloads\_workload\_upload\_results** > src\_app\_api\_cloud\_node\_workloads\_workload\_upload\_results(uuid, cloud\_node\_workload\_result\_schema) Workload Upload Results Handle the result of uploaded files for a Cloud Node workload. This endpoint is called by the Cloud Node after files have been uploaded to signed URLs. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.cloud_node_workload_result_schema import CloudNodeWorkloadResultSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.CloudNodeWorkloadsApi(api_client) uuid = 'uuid_example' # str | cloud_node_workload_result_schema = cyberwave.rest.CloudNodeWorkloadResultSchema() # CloudNodeWorkloadResultSchema | try: # Workload Upload Results api_instance.src_app_api_cloud_node_workloads_workload_upload_results(uuid, cloud_node_workload_result_schema) except Exception as e: print("Exception when calling CloudNodeWorkloadsApi->src_app_api_cloud_node_workloads_workload_upload_results: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **cloud\_node\_workload\_result\_schema** | [**CloudNodeWorkloadResultSchema**](/api-reference/rest/CloudNodeWorkloadResultSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # CloudeNodeHeartbeatResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudeNodeHeartbeatResponse # CloudeNodeHeartbeatResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | # CloudeNodeInstanceRegisterResponse Source: https://docs.cyberwave.com/api-reference/rest/CloudeNodeInstanceRegisterResponse # CloudeNodeInstanceRegisterResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | | **uuid** | **str** | | | | **slug** | **str** | | | # CombinedDatasetGenerationRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/CombinedDatasetGenerationRequestSchema # CombinedDatasetGenerationRequestSchema ## Properties | Name | Type | Description | Notes | | -------------------- | -------------- | ----------- | ----------- | | **twin\_uuids** | **List\[str]** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | | **var\_date** | **str** | | \[optional] | # CombinedRecordingGenerationRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/CombinedRecordingGenerationRequestSchema # CombinedRecordingGenerationRequestSchema ## Properties | Name | Type | Description | Notes | | -------------------- | -------------- | ----------- | ----------- | | **twin\_uuids** | **List\[str]** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | | **var\_date** | **str** | | \[optional] | # CompleteLargeUploadSchema Source: https://docs.cyberwave.com/api-reference/rest/CompleteLargeUploadSchema # CompleteLargeUploadSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ---------------------- | ----------- | ----------- | | **storage\_key** | **str** | | | | **metadata** | **Dict\[str, object]** | | \[optional] | # ControllerPolicyCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/ControllerPolicyCreateSchema # ControllerPolicyCreateSchema > stub: Valid `controller_type` values are `code`, `mlmodel`, `teleop`, `localop`, `motion`, `navigation`. ## Properties | Name | Type | Description | Notes | | -------------------- | ---------------------- | ----------- | ----------------------------------- | | **name** | **str** | | \[optional] \[default to ''] | | **visibility** | **str** | | \[optional] \[default to 'private'] | | **description** | **str** | | \[optional] \[default to ''] | | **controller\_type** | **str** | | | | **metadata** | **Dict\[str, object]** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **asset\_uuids** | **List\[str]** | | \[optional] | # ControllerPolicyExecuteResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/ControllerPolicyExecuteResponseSchema # ControllerPolicyExecuteResponseSchema ## Properties | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----------- | | **action\_id** | **str** | | \[optional] | | **status** | **str** | | | | **message** | **str** | | \[optional] | # ControllerPolicyExecuteSchema Source: https://docs.cyberwave.com/api-reference/rest/ControllerPolicyExecuteSchema # ControllerPolicyExecuteSchema ## Properties | Name | Type | Description | Notes | | -------------------------- | --------------------------------- | ----------- | --------------------------------- | | **twin\_uuid** | **str** | | | | **instruction** | **str** | | \[optional] | | **execution** | **str** | | \[optional] \[default to 'async'] | | **max\_steps** | **int** | | \[optional] | | **target\_left\_pos** | **List\[float]** | | \[optional] | | **target\_right\_pos** | **List\[float]** | | \[optional] | | **current\_joint\_states** | **Dict\[str, Dict\[str, float]]** | | \[optional] | | **server\_mode** | **bool** | | \[optional] \[default to False] | # ControllerPolicySchema Source: https://docs.cyberwave.com/api-reference/rest/ControllerPolicySchema # ControllerPolicySchema > stub: `controller_type` is generic (`code`, `mlmodel`, `teleop`, `localop`, `motion`, `navigation`). Robot-specific UX must key off asset `registry_id`, not controller type. ## Properties | Name | Type | Description | Notes | | -------------------- | ---------------------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **controller\_type** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **visibility** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **asset\_uuids** | **List\[str]** | | \[optional] | | **can\_write** | **bool** | | \[optional] \[default to False] | # ControllerPolicyUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/ControllerPolicyUpdateSchema # ControllerPolicyUpdateSchema > stub: Valid `controller_type` values are `code`, `mlmodel`, `teleop`, `localop`, `motion`, `navigation`. ## Properties | Name | Type | Description | Notes | | -------------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **controller\_type** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **visibility** | **str** | | \[optional] | | **asset\_uuids** | **List\[str]** | | \[optional] | # CreateAlertSchema Source: https://docs.cyberwave.com/api-reference/rest/CreateAlertSchema # CreateAlertSchema Schema for creating an Alert. ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----------------------------------- | | **name** | **str** | | | | **description** | **str** | | \[optional] \[default to ''] | | **media** | **str** | | \[optional] | | **alert\_type** | **str** | | \[optional] \[default to ''] | | **severity** | **str** | | \[optional] \[default to 'warning'] | | **source\_type** | **str** | | \[optional] \[default to 'edge'] | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **workflow\_uuid** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **force** | **bool** | | \[optional] \[default to False] | # CreateAssetFromPromptOrImageRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/CreateAssetFromPromptOrImageRequestSchema # CreateAssetFromPromptOrImageRequestSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------- | -------------------------------------------------------------- | ----------------------------------- | | **asset\_name** | **str** | | | | **prompt** | **str** | | \[optional] | | **image\_url** | **str** | | \[optional] | | **image\_bytes** | **binary** | Uploaded source image. Provide this, `prompt`, or `image_url`. | \[optional] | | **description** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] \[default to 'private'] | # CreateMissionExecutionSchema Source: https://docs.cyberwave.com/api-reference/rest/CreateMissionExecutionSchema # CreateMissionExecutionSchema Schema for creating a mission execution. ## Properties | Name | Type | Description | Notes | | -------------------- | ---------------------- | ----------- | ------------------------------- | | **parameters** | **Dict\[str, object]** | | \[optional] | | **priority** | **int** | | \[optional] | | **start\_at** | **str** | | \[optional] | | **dry\_run** | **bool** | | \[optional] \[default to False] | | **idempotency\_key** | **str** | | \[optional] | # CreateMissionSchema Source: https://docs.cyberwave.com/api-reference/rest/CreateMissionSchema # CreateMissionSchema Schema for creating a mission definition. ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------------------------------------------------- | ----------- | ---------------------------- | | **name** | **str** | | \[optional] \[default to ''] | | **description** | **str** | | \[optional] \[default to ''] | | **task\_sequence** | [**List\[TaskStepSchema\]**](/api-reference/rest/TaskStepSchema) | | | # CreateTaskSchema Source: https://docs.cyberwave.com/api-reference/rest/CreateTaskSchema # CreateTaskSchema Schema for creating a task. ## Properties | Name | Type | Description | Notes | | ---------------------------- | ---------------------- | ----------- | ----------------------------------- | | **name** | **str** | | | | **description** | **str** | | \[optional] \[default to ''] | | **task\_type** | **str** | | | | **controller\_policy\_uuid** | **str** | | \[optional] | | **default\_parameters** | **Dict\[str, object]** | | \[optional] | | **workspace\_uuid** | **str** | | | | **visibility** | **str** | | \[optional] \[default to 'private'] | # DatasetCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/DatasetCreateSchema # DatasetCreateSchema ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------- | --------------------------------------------------------------------------------- | ----------- | | **episodes** | **List\[str]** | | | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **include\_audio** | **bool** | Include microphone audio in the export as per-episode sidecar files. Default off. | \[optional] | # DatasetGenerationRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/DatasetGenerationRequestSchema # DatasetGenerationRequestSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | # DatasetGenerationRequestSchemaByDate Source: https://docs.cyberwave.com/api-reference/rest/DatasetGenerationRequestSchemaByDate # DatasetGenerationRequestSchemaByDate ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **var\_date** | **str** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | # DatasetGenerationResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/DatasetGenerationResponseSchema # DatasetGenerationResponseSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **task\_id** | **str** | | | | **status** | **str** | | | | **message** | **str** | | | # DatasetSchema Source: https://docs.cyberwave.com/api-reference/rest/DatasetSchema # DatasetSchema ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **episodes** | **List\[str]** | | | | **description** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | # DatasetUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/DatasetUpdateSchema # DatasetUpdateSchema ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------- | ----------- | ----------- | | **episodes** | **List\[str]** | | \[optional] | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # DatasetZipUrlSchema Source: https://docs.cyberwave.com/api-reference/rest/DatasetZipUrlSchema # DatasetZipUrlSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **zip\_url** | **str** | | | # DefaultApi Source: https://docs.cyberwave.com/api-reference/rest/DefaultApi # cyberwave.rest.DefaultApi All URIs are relative to *[http://localhost](http://localhost)* | Method | HTTP request | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------- | | [**src\_app\_api\_alerts\_acknowledge\_alert**](#src_app_api_alerts_acknowledge_alert) | **POST** `/api/v1/alerts/{uuid}/acknowledge` | Acknowledge Alert | | [**src\_app\_api\_alerts\_create\_alert**](#src_app_api_alerts_create_alert) | **POST** /api/v1/alerts | Create Alert | | [**src\_app\_api\_alerts\_delete\_alert**](#src_app_api_alerts_delete_alert) | **DELETE** `/api/v1/alerts/{uuid}` | Delete Alert | | [**src\_app\_api\_alerts\_get\_alert**](#src_app_api_alerts_get_alert) | **GET** `/api/v1/alerts/{uuid}` | Get Alert | | [**src\_app\_api\_alerts\_list\_alerts**](#src_app_api_alerts_list_alerts) | **GET** /api/v1/alerts | List Alerts | | [**src\_app\_api\_alerts\_resolve\_alert**](#src_app_api_alerts_resolve_alert) | **POST** `/api/v1/alerts/{uuid}/resolve` | Resolve Alert | | [**src\_app\_api\_alerts\_silence\_alert**](#src_app_api_alerts_silence_alert) | **POST** `/api/v1/alerts/{uuid}/silence` | Silence Alert | | [**src\_app\_api\_alerts\_update\_alert**](#src_app_api_alerts_update_alert) | **PUT** `/api/v1/alerts/{uuid}` | Update Alert | | [**src\_app\_api\_assets\_check\_registry\_id\_availability**](#src_app_api_assets_check_registry_id_availability) | **GET** `/api/v1/assets/check-registry-id/{registry_id}` | Check Registry Id Availability | | [**src\_app\_api\_assets\_complete\_large\_glb\_upload**](#src_app_api_assets_complete_large_glb_upload) | **POST** `/api/v1/assets/{uuid}/complete-large-glb-upload` | Complete Large Glb Upload | | [**src\_app\_api\_assets\_create\_asset**](#src_app_api_assets_create_asset) | **POST** /api/v1/assets | Create Asset | | [**src\_app\_api\_assets\_create\_asset\_from\_prompt\_or\_image**](#src_app_api_assets_create_asset_from_prompt_or_image) | **POST** /api/v1/assets/create-from-prompt-or-image | Create Asset From Prompt Or Image | | [**src\_app\_api\_assets\_create\_asset\_with\_urdf**](#src_app_api_assets_create_asset_with_urdf) | **POST** /api/v1/assets/create-with-urdf | Create Asset With Urdf | | [**src\_app\_api\_assets\_delete\_asset**](#src_app_api_assets_delete_asset) | **DELETE** `/api/v1/assets/{uuid}` | Delete Asset | | [**src\_app\_api\_assets\_export\_asset**](#src_app_api_assets_export_asset) | **GET** `/api/v1/assets/{uuid}/export` | Export Asset | | [**src\_app\_api\_assets\_get\_asset**](#src_app_api_assets_get_asset) | **GET** `/api/v1/assets/{uuid}` | Get Asset | | [**src\_app\_api\_assets\_get\_asset\_controllers**](#src_app_api_assets_get_asset_controllers) | **GET** `/api/v1/assets/{uuid}/controllers` | Get Asset Controllers | | [**src\_app\_api\_assets\_get\_asset\_kinematics**](#src_app_api_assets_get_asset_kinematics) | **GET** `/api/v1/assets/{uuid}/kinematics` | Get Asset Kinematics | | [**src\_app\_api\_assets\_get\_asset\_universal\_schema**](#src_app_api_assets_get_asset_universal_schema) | **GET** `/api/v1/assets/{uuid}/universal-schema` | Get Asset Universal Schema | | [**src\_app\_api\_assets\_get\_asset\_universal\_schema\_at\_path**](#src_app_api_assets_get_asset_universal_schema_at_path) | **GET** `/api/v1/assets/{uuid}/universal-schema/at` | Get Asset Universal Schema At Path | | [**src\_app\_api\_assets\_get\_popular\_tags**](#src_app_api_assets_get_popular_tags) | **GET** /api/v1/assets/popular-tags | Get Popular Tags | | [**src\_app\_api\_assets\_get\_public\_vendors**](#src_app_api_assets_get_public_vendors) | **GET** /api/v1/assets/public-vendors | Get Public Vendors | | [**src\_app\_api\_assets\_import\_asset\_package**](#src_app_api_assets_import_asset_package) | **POST** /api/v1/assets/import | Import Asset Package | | [**src\_app\_api\_assets\_import\_catalog\_asset**](#src_app_api_assets_import_catalog_asset) | **POST** /api/v1/assets/import-catalog | Import Catalog Asset | | [**src\_app\_api\_assets\_initiate\_large\_glb\_upload**](#src_app_api_assets_initiate_large_glb_upload) | **POST** `/api/v1/assets/{uuid}/initiate-large-glb-upload` | Initiate Large Glb Upload | | [**src\_app\_api\_assets\_list\_assets**](#src_app_api_assets_list_assets) | **GET** /api/v1/assets | List Assets | | [**src\_app\_api\_assets\_llm\_generation**](#src_app_api_assets_llm_generation) | **POST** `/api/v1/assets/{uuid}/llm-generation` | Llm Generation | | [**src\_app\_api\_assets\_patch\_asset\_universal\_schema**](#src_app_api_assets_patch_asset_universal_schema) | **PATCH** `/api/v1/assets/{uuid}/universal-schema` | Patch Asset Universal Schema | | [**src\_app\_api\_assets\_rebuild\_asset\_universal\_schema**](#src_app_api_assets_rebuild_asset_universal_schema) | **POST** `/api/v1/assets/{uuid}/universal-schema/rebuild` | Rebuild Asset Universal Schema | | [**src\_app\_api\_assets\_set\_glb\_from\_attachment**](#src_app_api_assets_set_glb_from_attachment) | **POST** `/api/v1/assets/{uuid}/glb-from-attachment` | Set Glb From Attachment | | [**src\_app\_api\_assets\_update\_asset**](#src_app_api_assets_update_asset) | **PUT** `/api/v1/assets/{uuid}` | Update Asset | | [**src\_app\_api\_assets\_upload\_glb**](#src_app_api_assets_upload_glb) | **POST** `/api/v1/assets/{uuid}/glb-file` | Upload Glb | | [**src\_app\_api\_assets\_upload\_thumbnail\_file**](#src_app_api_assets_upload_thumbnail_file) | **POST** `/api/v1/assets/{uuid}/thumbnail-file` | Upload Thumbnail File | | [**src\_app\_api\_assets\_vlm\_generation**](#src_app_api_assets_vlm_generation) | **POST** `/api/v1/assets/{uuid}/vlm-generation` | Vlm Generation | | [**src\_app\_api\_attachments\_complete\_large\_attachment\_upload**](#src_app_api_attachments_complete_large_attachment_upload) | **POST** `/api/v1/attachments/{uuid}/complete-large-upload` | Complete Large Attachment Upload | | [**src\_app\_api\_attachments\_create\_attachment**](#src_app_api_attachments_create_attachment) | **POST** /api/v1/attachments | Create Attachment | | [**src\_app\_api\_attachments\_delete\_attachment**](#src_app_api_attachments_delete_attachment) | **DELETE** `/api/v1/attachments/{uuid}` | Delete Attachment | | [**src\_app\_api\_attachments\_download\_attachment**](#src_app_api_attachments_download_attachment) | **GET** `/api/v1/attachments/{uuid}/download` | Download Attachment | | [**src\_app\_api\_attachments\_get\_attachment**](#src_app_api_attachments_get_attachment) | **GET** `/api/v1/attachments/{uuid}` | Get Attachment | | [**src\_app\_api\_attachments\_initiate\_large\_attachment\_upload**](#src_app_api_attachments_initiate_large_attachment_upload) | **POST** `/api/v1/attachments/{uuid}/initiate-large-upload` | Initiate Large Attachment Upload | | [**src\_app\_api\_attachments\_list\_attachments**](#src_app_api_attachments_list_attachments) | **GET** /api/v1/attachments | List Attachments | | [**src\_app\_api\_attachments\_update\_attachment**](#src_app_api_attachments_update_attachment) | **PUT** `/api/v1/attachments/{uuid}` | Update Attachment | | [**src\_app\_api\_attachments\_upload\_attachment**](#src_app_api_attachments_upload_attachment) | **POST** `/api/v1/attachments/{uuid}/upload` | Upload Attachment | | [**src\_app\_api\_controller\_policies\_clone\_controller\_policy**](#src_app_api_controller_policies_clone_controller_policy) | **POST** `/api/v1/controller-policies/{uuid}/clone` | Clone Controller Policy | | [**src\_app\_api\_controller\_policies\_create\_controller\_policy**](#src_app_api_controller_policies_create_controller_policy) | **POST** /api/v1/controller-policies | Create Controller Policy | | [**src\_app\_api\_controller\_policies\_delete\_controller\_policy**](#src_app_api_controller_policies_delete_controller_policy) | **DELETE** `/api/v1/controller-policies/{uuid}` | Delete Controller Policy | | [**src\_app\_api\_controller\_policies\_execute\_controller\_policy**](#src_app_api_controller_policies_execute_controller_policy) | **POST** `/api/v1/controller-policies/{uuid}/execute` | Execute Controller Policy | | [**src\_app\_api\_controller\_policies\_get\_action\_from\_policy**](#src_app_api_controller_policies_get_action_from_policy) | **GET** `/api/v1/controller-policies/{uuid}/action` | Get Action From Policy | | [**src\_app\_api\_controller\_policies\_get\_controller\_policy**](#src_app_api_controller_policies_get_controller_policy) | **GET** `/api/v1/controller-policies/{uuid}` | Get Controller Policy | | [**src\_app\_api\_controller\_policies\_list\_controller\_policies**](#src_app_api_controller_policies_list_controller_policies) | **GET** /api/v1/controller-policies | List Controller Policies | | [**src\_app\_api\_controller\_policies\_update\_controller\_policy**](#src_app_api_controller_policies_update_controller_policy) | **PUT** `/api/v1/controller-policies/{uuid}` | Update Controller Policy | | [**src\_app\_api\_datasets\_create\_dataset**](#src_app_api_datasets_create_dataset) | **POST** /api/v1/datasets | Create Dataset | | [**src\_app\_api\_datasets\_delete\_dataset**](#src_app_api_datasets_delete_dataset) | **DELETE** `/api/v1/datasets/{uuid}` | Delete Dataset | | [**src\_app\_api\_datasets\_get\_dataset**](#src_app_api_datasets_get_dataset) | **GET** `/api/v1/datasets/{uuid}` | Get Dataset | | [**src\_app\_api\_datasets\_get\_dataset\_zip\_url**](#src_app_api_datasets_get_dataset_zip_url) | **GET** `/api/v1/datasets/{uuid}/zip` | Get Dataset Zip Url | | [**src\_app\_api\_datasets\_list\_datasets**](#src_app_api_datasets_list_datasets) | **GET** /api/v1/datasets | List Datasets | | [**src\_app\_api\_datasets\_remove\_episode\_from\_dataset**](#src_app_api_datasets_remove_episode_from_dataset) | **DELETE** `/api/v1/datasets/{uuid}/episodes/{episode_uuid}` | Remove Episode From Dataset | | [**src\_app\_api\_datasets\_update\_dataset**](#src_app_api_datasets_update_dataset) | **PUT** `/api/v1/datasets/{uuid}` | Update Dataset | | [**src\_app\_api\_edge\_nodes\_discover\_twins**](#src_app_api_edge_nodes_discover_twins) | **POST** /api/v1/edges/discover | Discover Twins | | [**src\_app\_api\_edge\_nodes\_get\_edge\_twins**](#src_app_api_edge_nodes_get_edge_twins) | **GET** `/api/v1/edges/{uuid}/twins` | Get Edge Twins | | [**src\_app\_api\_edge\_nodes\_pair\_twin\_to\_edge**](#src_app_api_edge_nodes_pair_twin_to_edge) | **POST** `/api/v1/edges/{uuid}/pair` | Pair Twin To Edge | | [**src\_app\_api\_edge\_nodes\_restart\_edge\_core**](#src_app_api_edge_nodes_restart_edge_core) | **POST** `/api/v1/edges/{uuid}/restart-core` | Restart Edge Core | | [**src\_app\_api\_edge\_nodes\_unpair\_twin\_from\_edge**](#src_app_api_edge_nodes_unpair_twin_from_edge) | **DELETE** `/api/v1/edges/{uuid}/twins/{twin_uuid}` | Unpair Twin From Edge | | [**src\_app\_api\_edge\_nodes\_update\_camera\_config**](#src_app_api_edge_nodes_update_camera_config) | **PUT** `/api/v1/edges/{uuid}/twins/{twin_uuid}/camera-config` | Update Camera Config | | [**src\_app\_api\_edges\_create\_edge**](#src_app_api_edges_create_edge) | **POST** /api/v1/edges | Create Edge | | [**src\_app\_api\_edges\_delete\_edge**](#src_app_api_edges_delete_edge) | **DELETE** `/api/v1/edges/{uuid}` | Delete Edge | | [**src\_app\_api\_edges\_get\_edge**](#src_app_api_edges_get_edge) | **GET** `/api/v1/edges/{uuid}` | Get Edge | | [**src\_app\_api\_edges\_get\_edges**](#src_app_api_edges_get_edges) | **GET** /api/v1/edges | Get Edges | | [**src\_app\_api\_edges\_update\_edge**](#src_app_api_edges_update_edge) | **PUT** `/api/v1/edges/{uuid}` | Update Edge | | [**src\_app\_api\_environments\_cancel\_environment\_invitation**](#src_app_api_environments_cancel_environment_invitation) | **DELETE** `/api/v1/environments/invitations/{invitation_uuid}` | Cancel Environment Invitation | | [**src\_app\_api\_environments\_create\_environment\_for\_project**](#src_app_api_environments_create_environment_for_project) | **POST** `/api/v1/projects/{uuid}/environments` | Create Environment For Project | | [**src\_app\_api\_environments\_create\_environment\_link**](#src_app_api_environments_create_environment_link) | **POST** `/api/v1/environments/{uuid}/create-link` | Create Environment Link | | [**src\_app\_api\_environments\_create\_environment\_simulation**](#src_app_api_environments_create_environment_simulation) | **POST** `/api/v1/environments/{uuid}/simulations` | Create Environment Simulation | | [**src\_app\_api\_environments\_create\_environment\_snapshot**](#src_app_api_environments_create_environment_snapshot) | **POST** `/api/v1/environments/{uuid}/snapshots` | Create Environment Snapshot | | [**src\_app\_api\_environments\_add\_environment\_waypoints**](#src_app_api_environments_add_environment_waypoints) | **POST** `/api/v1/environments/{uuid}/waypoints` | Add Environment Waypoints | | [**src\_app\_api\_environments\_create\_standalone\_environment**](#src_app_api_environments_create_standalone_environment) | **POST** /api/v1/environments | Create Standalone Environment | | [**src\_app\_api\_environments\_delete\_environment**](#src_app_api_environments_delete_environment) | **DELETE** `/api/v1/environments/{uuid}` | Delete Environment | | [**src\_app\_api\_environments\_delete\_environment\_for\_project**](#src_app_api_environments_delete_environment_for_project) | **DELETE** `/api/v1/projects/{project_uuid}/environments/{uuid}` | Delete Environment For Project | | [**src\_app\_api\_environments\_delete\_environment\_snapshot**](#src_app_api_environments_delete_environment_snapshot) | **DELETE** `/api/v1/environments/{uuid}/snapshots/{snapshot_uuid}` | Delete Environment Snapshot | | [**src\_app\_api\_environments\_delete\_environment\_waypoint**](#src_app_api_environments_delete_environment_waypoint) | **DELETE** `/api/v1/environments/{uuid}/waypoints/{waypoint_id}` | Delete Environment Waypoint | | [**src\_app\_api\_environments\_delete\_recording**](#src_app_api_environments_delete_recording) | **DELETE** `/api/v1/environments/{uuid}/recordings/{recording_uuid}` | Delete Recording | | [**src\_app\_api\_environments\_generate\_telemetry\_recording**](#src_app_api_environments_generate_telemetry_recording) | **POST** `/api/v1/environments/{uuid}/generate-recording` | Generate Telemetry Recording | | [**src\_app\_api\_environments\_get\_environment**](#src_app_api_environments_get_environment) | **GET** `/api/v1/environments/{uuid}` | Get Environment | | [**src\_app\_api\_environments\_get\_environment\_dirty\_twins**](#src_app_api_environments_get_environment_dirty_twins) | **GET** `/api/v1/environments/{uuid}/schema/dirty_twins` | Get Environment Dirty Twins | | [**src\_app\_api\_environments\_get\_environment\_waypoints**](#src_app_api_environments_get_environment_waypoints) | **GET** `/api/v1/environments/{uuid}/waypoints` | Get Environment Waypoints | | [**src\_app\_api\_environments\_get\_environment\_invitations**](#src_app_api_environments_get_environment_invitations) | **GET** `/api/v1/environments/{uuid}/invitations` | Get Environment Invitations | | [**src\_app\_api\_environments\_get\_environment\_mujoco\_scene**](#src_app_api_environments_get_environment_mujoco_scene) | **GET** `/api/v1/environments/{uuid}/mujoco-scene` | Get Environment Mujoco Scene | | [**src\_app\_api\_environments\_get\_environment\_mujoco\_scene\_xml**](#src_app_api_environments_get_environment_mujoco_scene_xml) | **GET** `/api/v1/environments/{uuid}/mujoco-scene.xml` | Get Environment Mujoco Scene Xml | | [**src\_app\_api\_environments\_get\_environment\_mujoco\_scene\_zip\_direct**](#src_app_api_environments_get_environment_mujoco_scene_zip_direct) | **GET** `/api/v1/environments/{uuid}/mujoco-scene.zip` | Get Environment Mujoco Scene Zip Direct | | [**src\_app\_api\_environments\_get\_environment\_recordings**](#src_app_api_environments_get_environment_recordings) | **GET** `/api/v1/environments/{uuid}/recordings` | Get Environment Recordings | | [**src\_app\_api\_environments\_get\_environment\_sessions**](#src_app_api_environments_get_environment_sessions) | **GET** `/api/v1/environments/{uuid}/sessions` | Get Environment Sessions | | [**src\_app\_api\_environments\_get\_environment\_sharing\_info\_endpoint**](#src_app_api_environments_get_environment_sharing_info_endpoint) | **GET** `/api/v1/environments/{uuid}/sharing` | Get Environment Sharing Info Endpoint | | [**src\_app\_api\_environments\_get\_environment\_simulations**](#src_app_api_environments_get_environment_simulations) | **GET** `/api/v1/environments/{uuid}/simulations` | Get Environment Simulations | | [**src\_app\_api\_environments\_get\_environment\_snapshot**](#src_app_api_environments_get_environment_snapshot) | **GET** `/api/v1/environments/{uuid}/snapshots/{snapshot_uuid}` | Get Environment Snapshot | | [**src\_app\_api\_environments\_get\_environment\_snapshot\_hash**](#src_app_api_environments_get_environment_snapshot_hash) | **GET** `/api/v1/environments/{uuid}/snapshot-hash` | Get Environment Snapshot Hash | | [**src\_app\_api\_environments\_get\_environment\_twins**](#src_app_api_environments_get_environment_twins) | **GET** `/api/v1/environments/{uuid}/twins` | Get Environment Twins | | [**src\_app\_api\_environments\_get\_environment\_universal\_schema**](#src_app_api_environments_get_environment_universal_schema) | **GET** `/api/v1/environments/{uuid}/universal-schema` | Get Environment Universal Schema | | [**src\_app\_api\_environments\_get\_environment\_universal\_schema\_json**](#src_app_api_environments_get_environment_universal_schema_json) | **GET** `/api/v1/environments/{uuid}/universal-schema.json` | Get Environment Universal Schema Json | | [**src\_app\_api\_environments\_get\_environment\_urdf\_bundle**](#src_app_api_environments_get_environment_urdf_bundle) | **GET** `/api/v1/environments/{uuid}/urdf-bundle` | Get Environment Urdf Bundle | | [**src\_app\_api\_environments\_get\_environment\_urdf\_scene**](#src_app_api_environments_get_environment_urdf_scene) | **GET** `/api/v1/environments/{uuid}/urdf-scene` | Get Environment Urdf Scene | | [**src\_app\_api\_environments\_get\_environment\_urdf\_scene\_zip\_direct**](#src_app_api_environments_get_environment_urdf_scene_zip_direct) | **GET** `/api/v1/environments/{uuid}/urdf-scene.zip` | Get Environment Urdf Scene Zip Direct | | [**src\_app\_api\_environments\_get\_my\_environment\_permissions**](#src_app_api_environments_get_my_environment_permissions) | **GET** `/api/v1/environments/{uuid}/my-permissions` | Get My Environment Permissions | | [**src\_app\_api\_environments\_get\_recording\_data**](#src_app_api_environments_get_recording_data) | **GET** `/api/v1/environments/{uuid}/recordings/{recording_uuid}/data` | Get Recording Data | | [**src\_app\_api\_environments\_import\_environment\_mujoco\_scene**](#src_app_api_environments_import_environment_mujoco_scene) | **POST** `/api/v1/environments/{uuid}/import/mujoco-scene` | Import Environment Mujoco Scene | | [**src\_app\_api\_environments\_import\_environment\_universal\_schema**](#src_app_api_environments_import_environment_universal_schema) | **POST** `/api/v1/environments/{uuid}/import/universal-schema` | Import Environment Universal Schema | | [**src\_app\_api\_environments\_import\_environment\_urdf**](#src_app_api_environments_import_environment_urdf) | **POST** `/api/v1/environments/{uuid}/import/urdf` | Import Environment Urdf | | [**src\_app\_api\_environments\_invite\_user\_to\_environment**](#src_app_api_environments_invite_user_to_environment) | **POST** `/api/v1/environments/{uuid}/invite` | Invite User To Environment | | [**src\_app\_api\_environments\_list\_all\_environments**](#src_app_api_environments_list_all_environments) | **GET** /api/v1/environments | List All Environments | | [**src\_app\_api\_environments\_list\_environment\_mission\_executions**](#src_app_api_environments_list_environment_mission_executions) | **GET** `/api/v1/environments/{uuid}/mission-executions` | List Environment Mission Executions | | [**src\_app\_api\_environments\_list\_environment\_snapshots**](#src_app_api_environments_list_environment_snapshots) | **GET** `/api/v1/environments/{uuid}/snapshots` | List Environment Snapshots | | [**src\_app\_api\_environments\_list\_environment\_task\_executions**](#src_app_api_environments_list_environment_task_executions) | **GET** `/api/v1/environments/{uuid}/task-executions` | List Environment Task Executions | | [**src\_app\_api\_environments\_list\_environments\_for\_project**](#src_app_api_environments_list_environments_for_project) | **GET** `/api/v1/projects/{uuid}/environments` | List Environments For Project | | [**src\_app\_api\_environments\_process\_all\_environment\_sessions**](#src_app_api_environments_process_all_environment_sessions) | **POST** `/api/v1/environments/{uuid}/process-all-sessions` | Process All Environment Sessions | | [**src\_app\_api\_environments\_remove\_user\_from\_environment**](#src_app_api_environments_remove_user_from_environment) | **DELETE** `/api/v1/environments/{uuid}/users/{user_id}` | Remove User From Environment | | [**src\_app\_api\_environments\_reset\_environment**](#src_app_api_environments_reset_environment) | **POST** `/api/v1/environments/{uuid}/reset` | Reset Environment | | [**src\_app\_api\_environments\_restore\_environment\_snapshot**](#src_app_api_environments_restore_environment_snapshot) | **PUT** `/api/v1/environments/{uuid}/snapshots/{snapshot_uuid}/restore` | Restore Environment Snapshot | | [**src\_app\_api\_environments\_revoke\_environment\_link**](#src_app_api_environments_revoke_environment_link) | **POST** `/api/v1/environments/{uuid}/revoke-link` | Revoke Environment Link | | [**src\_app\_api\_environments\_share\_environment\_with\_user**](#src_app_api_environments_share_environment_with_user) | **POST** `/api/v1/environments/{uuid}/share` | Share Environment With User | | [**src\_app\_api\_environments\_stop\_environment\_simulation**](#src_app_api_environments_stop_environment_simulation) | **POST** `/api/v1/environments/{uuid}/simulations/{simulation_id}/stop` | Stop Environment Simulation | | [**src\_app\_api\_environments\_update\_environment**](#src_app_api_environments_update_environment) | **PUT** `/api/v1/environments/{uuid}` | Update Environment | | [**src\_app\_api\_environments\_update\_environment\_for\_project**](#src_app_api_environments_update_environment_for_project) | **PUT** `/api/v1/projects/{project_uuid}/environments/{uuid}` | Update Environment For Project | | [**src\_app\_api\_environments\_update\_environment\_snapshot**](#src_app_api_environments_update_environment_snapshot) | **PUT** `/api/v1/environments/{uuid}/snapshots/{snapshot_uuid}` | Update Environment Snapshot | | [**src\_app\_api\_environments\_update\_recording\_metadata**](#src_app_api_environments_update_recording_metadata) | **PUT** `/api/v1/environments/{uuid}/recordings/{recording_uuid}` | Update Recording Metadata | | [**src\_app\_api\_episode\_create\_episode**](#src_app_api_episode_create_episode) | **POST** /api/v1/episodes | Create Episode | | [**src\_app\_api\_episode\_delete\_episode**](#src_app_api_episode_delete_episode) | **DELETE** `/api/v1/episodes/{uuid}` | Delete Episode | | [**src\_app\_api\_episode\_get\_episode**](#src_app_api_episode_get_episode) | **GET** `/api/v1/episodes/{uuid}` | Get Episode | | [**src\_app\_api\_episode\_list\_episode\_task\_names**](#src_app_api_episode_list_episode_task_names) | **GET** /api/v1/episodes/task-names | List Episode Task Names | | [**src\_app\_api\_episode\_list\_episodes**](#src_app_api_episode_list_episodes) | **GET** /api/v1/episodes | List Episodes | | [**src\_app\_api\_episode\_update\_episode**](#src_app_api_episode_update_episode) | **PUT** `/api/v1/episodes/{uuid}` | Update Episode | | [**src\_app\_api\_events\_create\_business\_event**](#src_app_api_events_create_business_event) | **POST** /api/v1/events | Create Business Event | | [**src\_app\_api\_events\_list\_live\_events**](#src_app_api_events_list_live_events) | **GET** /api/v1/events/live | List Live Events | | [**src\_app\_api\_executions\_get\_task\_execution**](#src_app_api_executions_get_task_execution) | **GET** `/api/v1/executions/{uuid}` | Get Task Execution | | [**src\_app\_api\_executions\_list\_task\_executions**](#src_app_api_executions_list_task_executions) | **GET** /api/v1/executions | List Task Executions | | [**src\_app\_api\_invitation\_router\_accept\_invitation\_endpoint**](#src_app_api_invitation_router_accept_invitation_endpoint) | **GET** `/api/v1/invitations/accept/{token}` | Accept Invitation Endpoint | | [**src\_app\_api\_invitation\_router\_get\_invitation\_info**](#src_app_api_invitation_router_get_invitation_info) | **GET** `/api/v1/invitations/info/{token}` | Get Invitation Info | | [**src\_app\_api\_keybindings\_create\_keybinding**](#src_app_api_keybindings_create_keybinding) | **POST** /api/v1/keybindings | Create Keybinding | | [**src\_app\_api\_keybindings\_delete\_keybinding**](#src_app_api_keybindings_delete_keybinding) | **DELETE** `/api/v1/keybindings/{uuid}` | Delete Keybinding | | [**src\_app\_api\_keybindings\_get\_keybinding**](#src_app_api_keybindings_get_keybinding) | **GET** `/api/v1/keybindings/{uuid}` | Get Keybinding | | [**src\_app\_api\_keybindings\_list\_keybindings**](#src_app_api_keybindings_list_keybindings) | **GET** /api/v1/keybindings | List Keybindings | | [**src\_app\_api\_keybindings\_update\_keybinding**](#src_app_api_keybindings_update_keybinding) | **PUT** `/api/v1/keybindings/{uuid}` | Update Keybinding | | [**src\_app\_api\_labs\_end\_milan\_lab\_session**](#src_app_api_labs_end_milan_lab_session) | **DELETE** /api/v1/labs/milan-so101/end-session | End Milan Lab Session | | [**src\_app\_api\_labs\_get\_milan\_lab\_status**](#src_app_api_labs_get_milan_lab_status) | **GET** /api/v1/labs/milan-so101/status | Get Milan Lab Status | | [**src\_app\_api\_labs\_request\_milan\_lab\_access**](#src_app_api_labs_request_milan_lab_access) | **POST** /api/v1/labs/milan-so101/request-access | Request Milan Lab Access | | [**src\_app\_api\_maps\_create\_map**](#src_app_api_maps_create_map) | **POST** /api/v1/maps | Create Map | | [**src\_app\_api\_maps\_delete\_map**](#src_app_api_maps_delete_map) | **DELETE** `/api/v1/maps/{uuid}` | Delete Map | | [**src\_app\_api\_maps\_download\_map\_data**](#src_app_api_maps_download_map_data) | **GET** `/api/v1/maps/{uuid}/data` | Download Map Data | | [**src\_app\_api\_maps\_finalize\_stream\_map**](#src_app_api_maps_finalize_stream_map) | **POST** `/api/v1/maps/{uuid}/stream-finalize` | Finalize Stream Map | | [**src\_app\_api\_maps\_get\_map**](#src_app_api_maps_get_map) | **GET** `/api/v1/maps/{uuid}` | Get Map | | [**src\_app\_api\_maps\_get\_map\_image**](#src_app_api_maps_get_map_image) | **GET** `/api/v1/maps/{uuid}/image` | Get Map Image | | [**src\_app\_api\_maps\_list\_environment\_maps**](#src_app_api_maps_list_environment_maps) | **GET** `/api/v1/maps/environments/{uuid}` | List Environment Maps | | [**src\_app\_api\_maps\_list\_maps**](#src_app_api_maps_list_maps) | **GET** /api/v1/maps | List Maps | | [**src\_app\_api\_maps\_list\_twin\_maps**](#src_app_api_maps_list_twin_maps) | **GET** `/api/v1/maps/twins/{uuid}` | List Twin Maps | | [**src\_app\_api\_maps\_start\_map\_from\_stream**](#src_app_api_maps_start_map_from_stream) | **POST** /api/v1/maps/stream-start | Start Map From Stream | | [**src\_app\_api\_maps\_stop\_map\_from\_stream**](#src_app_api_maps_stop_map_from_stream) | **POST** /api/v1/maps/stream-stop | Stop Map From Stream | | [**src\_app\_api\_missions\_cancel\_mission\_execution**](#src_app_api_missions_cancel_mission_execution) | **POST** `/api/v1/twins/{twin_uuid}/missions/{mission_uuid}/executions/{uuid}/cancel` | Cancel Mission Execution | | [**src\_app\_api\_missions\_create\_mission**](#src_app_api_missions_create_mission) | **POST** `/api/v1/twins/{uuid}/missions` | Create Mission | | [**src\_app\_api\_missions\_delete\_mission**](#src_app_api_missions_delete_mission) | **DELETE** `/api/v1/twins/{twin_uuid}/missions/{uuid}` | Delete Mission | | [**src\_app\_api\_missions\_execute\_mission**](#src_app_api_missions_execute_mission) | **POST** `/api/v1/twins/{twin_uuid}/missions/{uuid}/execute` | Execute Mission | | [**src\_app\_api\_missions\_get\_mission**](#src_app_api_missions_get_mission) | **GET** `/api/v1/twins/{twin_uuid}/missions/{uuid}` | Get Mission | | [**src\_app\_api\_missions\_get\_mission\_execution**](#src_app_api_missions_get_mission_execution) | **GET** `/api/v1/twins/{twin_uuid}/missions/{mission_uuid}/executions/{uuid}` | Get Mission Execution | | [**src\_app\_api\_missions\_list\_mission\_executions**](#src_app_api_missions_list_mission_executions) | **GET** `/api/v1/twins/{twin_uuid}/missions/{uuid}/executions` | List Mission Executions | | [**src\_app\_api\_missions\_list\_missions**](#src_app_api_missions_list_missions) | **GET** `/api/v1/twins/{uuid}/missions` | List Missions | | [**src\_app\_api\_mlmodels\_create\_mlmodel**](#src_app_api_mlmodels_create_mlmodel) | **POST** /api/v1/mlmodels | Create Mlmodel | | [**src\_app\_api\_mlmodels\_delete\_mlmodel**](#src_app_api_mlmodels_delete_mlmodel) | **DELETE** `/api/v1/mlmodels/{uuid}` | Delete Mlmodel | | [**src\_app\_api\_mlmodels\_get\_mlmodel**](#src_app_api_mlmodels_get_mlmodel) | **GET** `/api/v1/mlmodels/{uuid}` | Get Mlmodel | | [**src\_app\_api\_mlmodels\_get\_mlmodel\_weights**](#src_app_api_mlmodels_get_mlmodel_weights) | **GET** `/api/v1/mlmodels/{uuid}/weights` | Get Mlmodel Weights | | [**src\_app\_api\_mlmodels\_list\_mlmodels**](#src_app_api_mlmodels_list_mlmodels) | **GET** /api/v1/mlmodels | List Mlmodels | | [**src\_app\_api\_mlmodels\_update\_mlmodel**](#src_app_api_mlmodels_update_mlmodel) | **PUT** `/api/v1/mlmodels/{uuid}` | Update Mlmodel | | [**src\_app\_api\_mltrainings\_create\_mltraining**](#src_app_api_mltrainings_create_mltraining) | **POST** /api/v1/mltrainings | Create Mltraining | | [**src\_app\_api\_mltrainings\_delete\_mltraining**](#src_app_api_mltrainings_delete_mltraining) | **DELETE** `/api/v1/mltrainings/{uuid}` | Delete Mltraining | | [**src\_app\_api\_mltrainings\_deploy\_mltraining**](#src_app_api_mltrainings_deploy_mltraining) | **POST** `/api/v1/mltrainings/{uuid}/deploy` | Deploy Mltraining | | [**src\_app\_api\_mltrainings\_get\_deployed\_mltrainings**](#src_app_api_mltrainings_get_deployed_mltrainings) | **GET** /api/v1/mltrainings/deployed | Get Deployed Mltrainings | | [**src\_app\_api\_mltrainings\_get\_mltraining**](#src_app_api_mltrainings_get_mltraining) | **GET** `/api/v1/mltrainings/{uuid}` | Get Mltraining | | [**src\_app\_api\_mltrainings\_list\_mltrainings\_for\_user\_workspaces**](#src_app_api_mltrainings_list_mltrainings_for_user_workspaces) | **GET** /api/v1/mltrainings | List Mltrainings For User Workspaces | | [**src\_app\_api\_mltrainings\_update\_mltraining**](#src_app_api_mltrainings_update_mltraining) | **PUT** `/api/v1/mltrainings/{uuid}` | Update Mltraining | | [**src\_app\_api\_navigation\_execute\_twin\_navigation**](#src_app_api_navigation_execute_twin_navigation) | **POST** `/api/v1/twins/{uuid}/navigation` | Execute Twin Navigation | | [**src\_app\_api\_projects\_create\_project**](#src_app_api_projects_create_project) | **POST** /api/v1/projects | Create Project | | [**src\_app\_api\_projects\_create\_project\_link**](#src_app_api_projects_create_project_link) | **POST** `/api/v1/projects/{uuid}/create-link` | Create Project Link | | [**src\_app\_api\_projects\_delete\_project**](#src_app_api_projects_delete_project) | **DELETE** `/api/v1/projects/{uuid}` | Delete Project | | [**src\_app\_api\_projects\_get\_my\_project\_permissions**](#src_app_api_projects_get_my_project_permissions) | **GET** `/api/v1/projects/{uuid}/my-permissions` | Get My Project Permissions | | [**src\_app\_api\_projects\_get\_project**](#src_app_api_projects_get_project) | **GET** `/api/v1/projects/{uuid}` | Get Project | | [**src\_app\_api\_projects\_get\_project\_shares**](#src_app_api_projects_get_project_shares) | **GET** `/api/v1/projects/{uuid}/shares` | Get Project Shares | | [**src\_app\_api\_projects\_invite\_user\_to\_project**](#src_app_api_projects_invite_user_to_project) | **POST** `/api/v1/projects/{uuid}/invite` | Invite User To Project | | [**src\_app\_api\_projects\_list\_projects**](#src_app_api_projects_list_projects) | **GET** /api/v1/projects | List Projects | | [**src\_app\_api\_projects\_revoke\_project\_link**](#src_app_api_projects_revoke_project_link) | **POST** `/api/v1/projects/{uuid}/revoke-link` | Revoke Project Link | | [**src\_app\_api\_projects\_share\_project**](#src_app_api_projects_share_project) | **POST** `/api/v1/projects/{uuid}/share` | Share Project | | [**src\_app\_api\_projects\_unshare\_project**](#src_app_api_projects_unshare_project) | **POST** `/api/v1/projects/{uuid}/unshare` | Unshare Project | | [**src\_app\_api\_projects\_update\_project**](#src_app_api_projects_update_project) | **PUT** `/api/v1/projects/{uuid}` | Update Project | | [**src\_app\_api\_tagged\_frames\_create\_tagged\_frames**](#src_app_api_tagged_frames_create_tagged_frames) | **POST** /api/v1/tagged-frames | Create Tagged Frames | | [**src\_app\_api\_tagged\_frames\_delete\_tagged\_frames**](#src_app_api_tagged_frames_delete_tagged_frames) | **DELETE** `/api/v1/tagged-frames/{uuid}` | Delete Tagged Frames | | [**src\_app\_api\_tagged\_frames\_get\_tagged\_frames**](#src_app_api_tagged_frames_get_tagged_frames) | **GET** `/api/v1/tagged-frames/{uuid}` | Get Tagged Frames | | [**src\_app\_api\_tagged\_frames\_list\_tagged\_frames**](#src_app_api_tagged_frames_list_tagged_frames) | **GET** /api/v1/tagged-frames | List Tagged Frames | | [**src\_app\_api\_tagged\_frames\_update\_tagged\_frames**](#src_app_api_tagged_frames_update_tagged_frames) | **PUT** `/api/v1/tagged-frames/{uuid}` | Update Tagged Frames | | [**src\_app\_api\_tasks\_cancel\_task\_execution**](#src_app_api_tasks_cancel_task_execution) | **POST** `/api/v1/tasks/executions/{uuid}/cancel` | Cancel Task Execution | | [**src\_app\_api\_tasks\_create\_task**](#src_app_api_tasks_create_task) | **POST** /api/v1/tasks | Create Task | | [**src\_app\_api\_tasks\_delete\_task**](#src_app_api_tasks_delete_task) | **DELETE** `/api/v1/tasks/{uuid}` | Delete Task | | [**src\_app\_api\_tasks\_execute\_task**](#src_app_api_tasks_execute_task) | **POST** `/api/v1/tasks/{uuid}/execute` | Execute Task | | [**src\_app\_api\_tasks\_get\_task**](#src_app_api_tasks_get_task) | **GET** `/api/v1/tasks/{uuid}` | Get Task | | [**src\_app\_api\_tasks\_get\_task\_execution**](#src_app_api_tasks_get_task_execution) | **GET** `/api/v1/tasks/executions/{uuid}` | Get Task Execution | | [**src\_app\_api\_tasks\_list\_task\_queue**](#src_app_api_tasks_list_task_queue) | **GET** /api/v1/tasks/queue | List Task Queue | | [**src\_app\_api\_tasks\_list\_tasks**](#src_app_api_tasks_list_tasks) | **GET** /api/v1/tasks | List Tasks | | [**src\_app\_api\_tasks\_update\_task**](#src_app_api_tasks_update_task) | **PUT** `/api/v1/tasks/{uuid}` | Update Task | | [**src\_app\_api\_twins\_create\_twin**](#src_app_api_twins_create_twin) | **POST** /api/v1/twins | Create Twin | | [**src\_app\_api\_twins\_delete\_twin**](#src_app_api_twins_delete_twin) | **DELETE** `/api/v1/twins/{uuid}` | Delete Twin | | [**src\_app\_api\_twins\_execute\_twin\_action**](#src_app_api_twins_execute_twin_action) | **POST** `/api/v1/twins/{uuid}/actions` | Execute Twin Action | | [**src\_app\_api\_twins\_get\_recording**](#src_app_api_twins_get_recording) | **GET** `/api/v1/twins/recordings/{recording_uuid}` | Get Recording | | [**src\_app\_api\_twins\_get\_twin**](#src_app_api_twins_get_twin) | **GET** `/api/v1/twins/{uuid}` | Get Twin | | [**src\_app\_api\_twins\_get\_twin\_action\_status**](#src_app_api_twins_get_twin_action_status) | **GET** `/api/v1/twins/{uuid}/actions/{action_id}` | Get Twin Action Status | | [**src\_app\_api\_twins\_get\_twin\_calibration**](#src_app_api_twins_get_twin_calibration) | **GET** `/api/v1/twins/{uuid}/calibration` | Get Twin Calibration | | [**src\_app\_api\_twins\_get\_twin\_connection\_history**](#src_app_api_twins_get_twin_connection_history) | **GET** `/api/v1/twins/{uuid}/connection-history` | Get Twin Connection History | | [**src\_app\_api\_twins\_get\_twin\_driver\_logs**](#src_app_api_twins_get_twin_driver_logs) | **GET** `/api/v1/twins/{uuid}/logs` | Get Twin Driver Logs | | [**src\_app\_api\_twins\_get\_twin\_latest\_frame**](#src_app_api_twins_get_twin_latest_frame) | **GET** `/api/v1/twins/{uuid}/latest-frame` | Get Twin Latest Frame | | [**src\_app\_api\_twins\_get\_twin\_latest\_metrics**](#src_app_api_twins_get_twin_latest_metrics) | **GET** `/api/v1/twins/{uuid}/metrics/latest` | Get Twin Latest Metrics | | [**src\_app\_api\_twins\_get\_twin\_links**](#src_app_api_twins_get_twin_links) | **GET** `/api/v1/twins/{uuid}/links` | Get Twin Links | | [**src\_app\_api\_twins\_get\_twin\_metrics**](#src_app_api_twins_get_twin_metrics) | **GET** `/api/v1/twins/{uuid}/metrics` | Get Twin Metrics | | [**src\_app\_api\_twins\_get\_twin\_motions**](#src_app_api_twins_get_twin_motions) | **GET** `/api/v1/twins/{uuid}/motions` | Get Twin Motions | | [**src\_app\_api\_twins\_get\_twin\_notebook**](#src_app_api_twins_get_twin_notebook) | **GET** `/api/v1/twins/{uuid}/notebook.ipynb` | Get Twin Notebook | | [**src\_app\_api\_twins\_get\_twin\_recordings**](#src_app_api_twins_get_twin_recordings) | **GET** `/api/v1/twins/{uuid}/recordings` | Get Twin Recordings | | [**src\_app\_api\_twins\_get\_twin\_universal\_schema\_at\_path**](#src_app_api_twins_get_twin_universal_schema_at_path) | **GET** `/api/v1/twins/{uuid}/universal-schema/at` | Get Twin Universal Schema At Path | | [**src\_app\_api\_twins\_link\_occupancy\_map**](#src_app_api_twins_link_occupancy_map) | **POST** `/api/v1/twins/{uuid}/occupancy-map` | Link Occupancy Map | | [**src\_app\_api\_twins\_list\_all\_twins**](#src_app_api_twins_list_all_twins) | **GET** /api/v1/twins | List All Twins | | [**src\_app\_api\_twins\_patch\_twin\_universal\_schema**](#src_app_api_twins_patch_twin_universal_schema) | **PATCH** `/api/v1/twins/{uuid}/universal-schema` | Patch Twin Universal Schema | | [**src\_app\_api\_twins\_reload\_twin\_capabilities**](#src_app_api_twins_reload_twin_capabilities) | **POST** `/api/v1/twins/{uuid}/reload-capabilities` | Reload Twin Capabilities | | [**src\_app\_api\_twins\_reload\_twins\_capabilities\_bulk**](#src_app_api_twins_reload_twins_capabilities_bulk) | **POST** /api/v1/twins/reload-capabilities | Reload Twins Capabilities Bulk | | [**src\_app\_api\_twins\_sync\_twin\_with\_asset**](#src_app_api_twins_sync_twin_with_asset) | **POST** `/api/v1/twins/{uuid}/sync-with-asset` | Sync Twin With Asset | | [**src\_app\_api\_twins\_update\_twin**](#src_app_api_twins_update_twin) | **PUT** `/api/v1/twins/{uuid}` | Update Twin | | [**src\_app\_api\_twins\_update\_twin\_calibration**](#src_app_api_twins_update_twin_calibration) | **POST** `/api/v1/twins/{uuid}/calibration` | Update Twin Calibration | | [**src\_app\_api\_twins\_update\_twin\_state**](#src_app_api_twins_update_twin_state) | **PATCH** `/api/v1/twins/{uuid}/state` | Update Twin State | | [**src\_app\_api\_urdf\_create\_urdf\_project**](#src_app_api_urdf_create_urdf_project) | **POST** /api/v1/urdf-projects | Create Urdf Project | | [**src\_app\_api\_urdf\_delete\_urdf\_project**](#src_app_api_urdf_delete_urdf_project) | **DELETE** `/api/v1/urdf-projects/{uuid}` | Delete Urdf Project | | [**src\_app\_api\_urdf\_fix\_urdf\_project\_slug**](#src_app_api_urdf_fix_urdf_project_slug) | **POST** `/api/v1/urdf-projects/{uuid}/fix-slug` | Fix Urdf Project Slug | | [**src\_app\_api\_urdf\_get\_twin\_joint\_state**](#src_app_api_urdf_get_twin_joint_state) | **GET** `/api/v1/twins/{uuid}/joints/{joint_name}/state` | Get Twin Joint State | | [**src\_app\_api\_urdf\_get\_twin\_joint\_states**](#src_app_api_urdf_get_twin_joint_states) | **GET** `/api/v1/twins/{uuid}/joint_states` | Get Twin Joint States | | [**src\_app\_api\_urdf\_get\_twin\_joints**](#src_app_api_urdf_get_twin_joints) | **GET** `/api/v1/twins/{uuid}/joints` | Get Twin Joints | | [**src\_app\_api\_urdf\_get\_twin\_robot\_description**](#src_app_api_urdf_get_twin_robot_description) | **GET** `/api/v1/twins/{uuid}/robot_description` | Get Twin Robot Description | | [**src\_app\_api\_urdf\_get\_twin\_urdf\_raw**](#src_app_api_urdf_get_twin_urdf_raw) | **GET** `/api/v1/twins/{uuid}/urdf` | Get Twin Urdf Raw | | [**src\_app\_api\_urdf\_get\_urdf\_project**](#src_app_api_urdf_get_urdf_project) | **GET** `/api/v1/urdf-projects/{uuid}` | Get Urdf Project | | [**src\_app\_api\_urdf\_list\_urdf\_projects**](#src_app_api_urdf_list_urdf_projects) | **GET** /api/v1/urdf-projects | List Urdf Projects | | [**src\_app\_api\_urdf\_update\_twin\_joint\_state**](#src_app_api_urdf_update_twin_joint_state) | **PUT** `/api/v1/twins/{uuid}/joints/{joint_name}/state` | Update Twin Joint State | | [**src\_app\_api\_urdf\_update\_twin\_joint\_states**](#src_app_api_urdf_update_twin_joint_states) | **PUT** `/api/v1/twins/{uuid}/joint_states` | Update Twin Joint States | | [**src\_app\_api\_urdf\_update\_urdf\_project**](#src_app_api_urdf_update_urdf_project) | **PUT** `/api/v1/urdf-projects/{uuid}` | Update Urdf Project | | [**src\_app\_api\_urdf\_upload\_zip\_file**](#src_app_api_urdf_upload_zip_file) | **POST** `/api/v1/urdf-projects/{uuid}/zip-file` | Upload Zip File | | [**src\_app\_api\_workflows\_activate\_workflow**](#src_app_api_workflows_activate_workflow) | **POST** `/api/v1/workflows/{uuid}/activate` | Activate Workflow | | [**src\_app\_api\_workflows\_cancel\_workflow\_execution**](#src_app_api_workflows_cancel_workflow_execution) | **POST** `/api/v1/workflows/executions/{execution_uuid}/cancel` | Cancel Workflow Execution | | [**src\_app\_api\_workflows\_create\_workflow**](#src_app_api_workflows_create_workflow) | **POST** /api/v1/workflows | Create Workflow | | [**src\_app\_api\_workflows\_create\_workflow\_connection**](#src_app_api_workflows_create_workflow_connection) | **POST** `/api/v1/workflows/{uuid}/connections` | Create Workflow Connection | | [**src\_app\_api\_workflows\_create\_workflow\_node**](#src_app_api_workflows_create_workflow_node) | **POST** `/api/v1/workflows/{uuid}/nodes` | Create Workflow Node | | [**src\_app\_api\_workflows\_deactivate\_workflow**](#src_app_api_workflows_deactivate_workflow) | **POST** `/api/v1/workflows/{uuid}/deactivate` | Deactivate Workflow | | [**src\_app\_api\_workflows\_delete\_workflow**](#src_app_api_workflows_delete_workflow) | **DELETE** `/api/v1/workflows/{uuid}` | Delete Workflow | | [**src\_app\_api\_workflows\_delete\_workflow\_connection**](#src_app_api_workflows_delete_workflow_connection) | **DELETE** `/api/v1/workflows/{uuid}/connections/{connection_uuid}` | Delete Workflow Connection | | [**src\_app\_api\_workflows\_delete\_workflow\_node**](#src_app_api_workflows_delete_workflow_node) | **DELETE** `/api/v1/workflows/{uuid}/nodes/{node_uuid}` | Delete Workflow Node | | [**src\_app\_api\_workflows\_edge\_sync\_workflows**](#src_app_api_workflows_edge_sync_workflows) | **GET** `/api/v1/workflows/edge-sync/{twin_uuid}` | Edge Sync Workflows | | [**src\_app\_api\_workflows\_execute\_workflow**](#src_app_api_workflows_execute_workflow) | **POST** `/api/v1/workflows/{uuid}/execute` | Execute Workflow | | [**src\_app\_api\_workflows\_get\_execution\_by\_uuid**](#src_app_api_workflows_get_execution_by_uuid) | **GET** `/api/v1/workflows/executions/{execution_uuid}` | Get Execution By Uuid | | [**src\_app\_api\_workflows\_get\_node\_schema**](#src_app_api_workflows_get_node_schema) | **GET** `/api/v1/workflows/node-schemas/{node_type}` | Get Node Schema | | [**src\_app\_api\_workflows\_get\_node\_schemas**](#src_app_api_workflows_get_node_schemas) | **GET** /api/v1/workflows/node-schemas | Get Node Schemas | | [**src\_app\_api\_workflows\_get\_workflow**](#src_app_api_workflows_get_workflow) | **GET** `/api/v1/workflows/{uuid}` | Get Workflow | | [**src\_app\_api\_workflows\_get\_workflow\_execution**](#src_app_api_workflows_get_workflow_execution) | **GET** `/api/v1/workflows/{uuid}/executions/{execution_uuid}` | Get Workflow Execution | | [**src\_app\_api\_workflows\_get\_workflow\_node**](#src_app_api_workflows_get_workflow_node) | **GET** `/api/v1/workflows/{uuid}/nodes/{node_uuid}` | Get Workflow Node | | [**src\_app\_api\_workflows\_list\_workflow\_connections**](#src_app_api_workflows_list_workflow_connections) | **GET** `/api/v1/workflows/{uuid}/connections` | List Workflow Connections | | [**src\_app\_api\_workflows\_list\_workflow\_executions**](#src_app_api_workflows_list_workflow_executions) | **GET** `/api/v1/workflows/{uuid}/executions` | List Workflow Executions | | [**src\_app\_api\_workflows\_list\_workflow\_nodes**](#src_app_api_workflows_list_workflow_nodes) | **GET** `/api/v1/workflows/{uuid}/nodes` | List Workflow Nodes | | [**src\_app\_api\_workflows\_list\_workflows**](#src_app_api_workflows_list_workflows) | **GET** /api/v1/workflows | List Workflows | | [**src\_app\_api\_workflows\_update\_workflow**](#src_app_api_workflows_update_workflow) | **PUT** `/api/v1/workflows/{uuid}` | Update Workflow | | [**src\_app\_api\_workflows\_update\_workflow\_node**](#src_app_api_workflows_update_workflow_node) | **PUT** `/api/v1/workflows/{uuid}/nodes/{node_uuid}` | Update Workflow Node | | [**src\_app\_api\_workflows\_validate\_node\_inputs**](#src_app_api_workflows_validate_node_inputs) | **POST** `/api/v1/workflows/nodes/{node_uuid}/validate-inputs` | Validate Node Inputs | | [**src\_users\_api\_organizations\_add\_organization\_member\_by\_email**](#src_users_api_organizations_add_organization_member_by_email) | **POST** `/api/v1/users/organizations/{uuid}/members` | Add Organization Member By Email | | [**src\_users\_api\_organizations\_create\_organization**](#src_users_api_organizations_create_organization) | **POST** /api/v1/users/organizations | Create Organization | | [**src\_users\_api\_organizations\_delete\_organization**](#src_users_api_organizations_delete_organization) | **DELETE** `/api/v1/users/organizations/{uuid}` | Delete Organization | | [**src\_users\_api\_organizations\_get\_organization**](#src_users_api_organizations_get_organization) | **GET** `/api/v1/users/organizations/{uuid}` | Get Organization | | [**src\_users\_api\_organizations\_get\_organization\_by\_slug**](#src_users_api_organizations_get_organization_by_slug) | **GET** `/api/v1/users/organizations/by-slug/{slug}` | Get Organization By Slug | | [**src\_users\_api\_organizations\_list\_organization\_members**](#src_users_api_organizations_list_organization_members) | **GET** `/api/v1/users/organizations/{uuid}/members` | List Organization Members | | [**src\_users\_api\_organizations\_list\_organization\_workspaces**](#src_users_api_organizations_list_organization_workspaces) | **GET** `/api/v1/users/organizations/{uuid}/workspaces` | List Organization Workspaces | | [**src\_users\_api\_organizations\_list\_organizations**](#src_users_api_organizations_list_organizations) | **GET** /api/v1/users/organizations | List Organizations | | [**src\_users\_api\_organizations\_remove\_organization\_member**](#src_users_api_organizations_remove_organization_member) | **DELETE** `/api/v1/users/organizations/{uuid}/members/{user_uuid}` | Remove Organization Member | | [**src\_users\_api\_organizations\_update\_organization**](#src_users_api_organizations_update_organization) | **PUT** `/api/v1/users/organizations/{uuid}` | Update Organization | | [**src\_users\_api\_organizations\_update\_organization\_member\_role**](#src_users_api_organizations_update_organization_member_role) | **PUT** `/api/v1/users/organizations/{uuid}/members/{user_uuid}/role` | Update Organization Member Role | | [**src\_users\_api\_plans\_get\_plan**](#src_users_api_plans_get_plan) | **GET** /api/v1/users/plan | Get Plan | | [**src\_users\_api\_workspaces\_add\_workspace\_member\_by\_email**](#src_users_api_workspaces_add_workspace_member_by_email) | **POST** `/api/v1/users/workspaces/{uuid}/add-member` | Add Workspace Member By Email | | [**src\_users\_api\_workspaces\_check\_workspace\_slug**](#src_users_api_workspaces_check_workspace_slug) | **GET** `/api/v1/users/workspaces/check-slug/{slug}` | Check Workspace Slug | | [**src\_users\_api\_workspaces\_create\_workspace**](#src_users_api_workspaces_create_workspace) | **POST** /api/v1/users/workspaces | Create Workspace | | [**src\_users\_api\_workspaces\_delete\_workspace**](#src_users_api_workspaces_delete_workspace) | **DELETE** `/api/v1/users/workspaces/{uuid}` | Delete Workspace | | [**src\_users\_api\_workspaces\_get\_default\_workspace**](#src_users_api_workspaces_get_default_workspace) | **GET** /api/v1/users/workspaces/default | Get Default Workspace | | [**src\_users\_api\_workspaces\_get\_vendor\_description**](#src_users_api_workspaces_get_vendor_description) | **GET** `/api/v1/users/vendors/{slug}/description` | Get Vendor Description | | [**src\_users\_api\_workspaces\_get\_workspace**](#src_users_api_workspaces_get_workspace) | **GET** `/api/v1/users/workspaces/{uuid}` | Get Workspace | | [**src\_users\_api\_workspaces\_get\_workspace\_by\_slug**](#src_users_api_workspaces_get_workspace_by_slug) | **GET** `/api/v1/users/workspaces/by-slug/{slug}` | Get Workspace By Slug | | [**src\_users\_api\_workspaces\_leave\_team**](#src_users_api_workspaces_leave_team) | **DELETE** `/api/v1/users/workspaces/{team_uuid}/members/{uuid}/leave` | Leave Team | | [**src\_users\_api\_workspaces\_list\_team\_members**](#src_users_api_workspaces_list_team_members) | **GET** `/api/v1/users/workspaces/{team_uuid}/members` | List Team Members | | [**src\_users\_api\_workspaces\_list\_workspaces**](#src_users_api_workspaces_list_workspaces) | **GET** /api/v1/users/workspaces | List Workspaces | | [**src\_users\_api\_workspaces\_remove\_team\_member**](#src_users_api_workspaces_remove_team_member) | **DELETE** `/api/v1/users/workspaces/{team_uuid}/members/{uuid}` | Remove Team Member | | [**src\_users\_api\_workspaces\_remove\_workspace\_member**](#src_users_api_workspaces_remove_workspace_member) | **DELETE** `/api/v1/users/workspaces/{uuid}/members/{user_uuid}` | Remove Workspace Member | | [**src\_users\_api\_workspaces\_set\_default\_workspace**](#src_users_api_workspaces_set_default_workspace) | **POST** /api/v1/users/workspaces/default | Set Default Workspace | | [**src\_users\_api\_workspaces\_update\_workspace**](#src_users_api_workspaces_update_workspace) | **PUT** `/api/v1/users/workspaces/{uuid}` | Update Workspace | | [**src\_users\_api\_workspaces\_update\_workspace\_member\_role**](#src_users_api_workspaces_update_workspace_member_role) | **PUT** `/api/v1/users/workspaces/{uuid}/members/{user_uuid}/role` | Update Workspace Member Role | # **src\_app\_api\_alerts\_acknowledge\_alert** > AlertSchema src\_app\_api\_alerts\_acknowledge\_alert(uuid) Acknowledge Alert Mark an alert as acknowledged. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Acknowledge Alert api_response = api_instance.src_app_api_alerts_acknowledge_alert(uuid) print("The response of DefaultApi->src_app_api_alerts_acknowledge_alert:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_acknowledge_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**AlertSchema**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_create\_alert** > AlertSchema src\_app\_api\_alerts\_create\_alert(create\_alert\_schema) Create Alert Create a new alert. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.models.create_alert_schema import CreateAlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) create_alert_schema = cyberwave.rest.CreateAlertSchema() # CreateAlertSchema | try: # Create Alert api_response = api_instance.src_app_api_alerts_create_alert(create_alert_schema) print("The response of DefaultApi->src_app_api_alerts_create_alert:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_create_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------------------------------------------------------------- | ----------- | ----- | | **create\_alert\_schema** | [**CreateAlertSchema**](/api-reference/rest/CreateAlertSchema) | | | ### Return type [**AlertSchema**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_delete\_alert** > src\_app\_api\_alerts\_delete\_alert(uuid) Delete Alert Delete an alert. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Alert api_instance.src_app_api_alerts_delete_alert(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_delete_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_get\_alert** > AlertSchema src\_app\_api\_alerts\_get\_alert(uuid) Get Alert Get an alert by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Alert api_response = api_instance.src_app_api_alerts_get_alert(uuid) print("The response of DefaultApi->src_app_api_alerts_get_alert:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_get_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**AlertSchema**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_list\_alerts** > List\[AlertSchema] src\_app\_api\_alerts\_list\_alerts(workspace\_uuid=workspace\_uuid, twin\_uuid=twin\_uuid, environment\_uuid=environment\_uuid, status=status, severity=severity, limit=limit) List Alerts List alerts visible to the authenticated user. Filters: * workspace\_uuid: Filter by workspace * twin\_uuid: Filter by twin * environment\_uuid: Filter by environment * status: Filter by status (comma-separated, e.g. "active,acknowledged") * severity: Filter by severity (comma-separated, e.g. "error,critical") * limit: Max results (default 100) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) workspace_uuid = 'workspace_uuid_example' # str | (optional) twin_uuid = 'twin_uuid_example' # str | (optional) environment_uuid = 'environment_uuid_example' # str | (optional) status = 'status_example' # str | (optional) severity = 'severity_example' # str | (optional) limit = 100 # int | (optional) (default to 100) try: # List Alerts api_response = api_instance.src_app_api_alerts_list_alerts(workspace_uuid=workspace_uuid, twin_uuid=twin_uuid, environment_uuid=environment_uuid, status=status, severity=severity, limit=limit) print("The response of DefaultApi->src_app_api_alerts_list_alerts:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_list_alerts: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------- | ------- | ----------- | ----------------------------- | | **workspace\_uuid** | **str** | | \[optional] | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **status** | **str** | | \[optional] | | **severity** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**List\[AlertSchema\]**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_resolve\_alert** > AlertSchema src\_app\_api\_alerts\_resolve\_alert(uuid) Resolve Alert Mark an alert as resolved. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Resolve Alert api_response = api_instance.src_app_api_alerts_resolve_alert(uuid) print("The response of DefaultApi->src_app_api_alerts_resolve_alert:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_resolve_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**AlertSchema**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_silence\_alert** > AlertSchema src\_app\_api\_alerts\_silence\_alert(uuid) Silence Alert Silence an alert workspace-wide without resolving the root cause. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Silence Alert api_response = api_instance.src_app_api_alerts_silence_alert(uuid) print("The response of DefaultApi->src_app_api_alerts_silence_alert:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_silence_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**AlertSchema**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_alerts\_update\_alert** > AlertSchema src\_app\_api\_alerts\_update\_alert(uuid, update\_alert\_schema) Update Alert Update an alert's mutable fields. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.alert_schema import AlertSchema from cyberwave.rest.models.update_alert_schema import UpdateAlertSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | update_alert_schema = cyberwave.rest.UpdateAlertSchema() # UpdateAlertSchema | try: # Update Alert api_response = api_instance.src_app_api_alerts_update_alert(uuid, update_alert_schema) print("The response of DefaultApi->src_app_api_alerts_update_alert:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_alerts_update_alert: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **update\_alert\_schema** | [**UpdateAlertSchema**](/api-reference/rest/UpdateAlertSchema) | | | ### Return type [**AlertSchema**](/api-reference/rest/AlertSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_check\_registry\_id\_availability** > src\_app\_api\_assets\_check\_registry\_id\_availability(registry\_id) Check Registry Id Availability Check if a registry\_id is available for use. Returns: - available: True if the registry\_id is not in use - registry\_id: The normalized registry\_id - suggestion: If not available, suggests an alternative ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) registry_id = 'registry_id_example' # str | try: # Check Registry Id Availability api_instance.src_app_api_assets_check_registry_id_availability(registry_id) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_check_registry_id_availability: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------- | ------- | ----------- | ----- | | **registry\_id** | **str** | | | ### Return type void (empty response body) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_complete\_large\_glb\_upload** > AssetSchema src\_app\_api\_assets\_complete\_large\_glb\_upload(uuid, complete\_large\_upload\_schema) Complete Large Glb Upload Complete a large GLB file upload for an asset. This moves the uploaded file to the asset's GLB field. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.models.complete_large_upload_schema import CompleteLargeUploadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | complete_large_upload_schema = cyberwave.rest.CompleteLargeUploadSchema() # CompleteLargeUploadSchema | try: # Complete Large Glb Upload api_response = api_instance.src_app_api_assets_complete_large_glb_upload(uuid, complete_large_upload_schema) print("The response of DefaultApi->src_app_api_assets_complete_large_glb_upload:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_complete_large_glb_upload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **complete\_large\_upload\_schema** | [**CompleteLargeUploadSchema**](/api-reference/rest/CompleteLargeUploadSchema) | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_create\_asset** > AssetSchema src\_app\_api\_assets\_create\_asset(asset\_create\_schema) Create Asset ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_create_schema import AssetCreateSchema from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) asset_create_schema = cyberwave.rest.AssetCreateSchema() # AssetCreateSchema | try: # Create Asset api_response = api_instance.src_app_api_assets_create_asset(asset_create_schema) print("The response of DefaultApi->src_app_api_assets_create_asset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_create_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------------------------------------------------------------- | ----------- | ----- | | **asset\_create\_schema** | [**AssetCreateSchema**](/api-reference/rest/AssetCreateSchema) | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_create\_asset\_from\_prompt\_or\_image** > DeferredTaskExecutionResponseSchema src\_app\_api\_assets\_create\_asset\_from\_prompt\_or\_image(asset\_name, prompt=prompt, image\_url=image\_url, image\_bytes=image\_bytes, description=description, workspace\_uuid=workspace\_uuid, visibility=visibility) Create Asset From Prompt Or Image Create a mesh from a text prompt (and optionally an image). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.deferred_task_execution_response_schema import DeferredTaskExecutionResponseSchema from cyberwave.rest.models.image_bytes import ImageBytes from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) asset_name = 'asset_name_example' # str | prompt = 'prompt_example' # str | (optional) image_url = 'image_url_example' # str | (optional) image_bytes = cyberwave.rest.ImageBytes() # ImageBytes | (optional) description = 'description_example' # str | (optional) workspace_uuid = 'workspace_uuid_example' # str | (optional) visibility = 'private' # str | (optional) (default to 'private') try: # Create Asset From Prompt Or Image api_response = api_instance.src_app_api_assets_create_asset_from_prompt_or_image(asset_name, prompt=prompt, image_url=image_url, image_bytes=image_bytes, description=description, workspace_uuid=workspace_uuid, visibility=visibility) print("The response of DefaultApi->src_app_api_assets_create_asset_from_prompt_or_image:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_create_asset_from_prompt_or_image: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------------------------------------------------ | ----------- | ----------------------------------- | | **asset\_name** | **str** | | | | **prompt** | **str** | | \[optional] | | **image\_url** | **str** | | \[optional] | | **image\_bytes** | [**ImageBytes**](/api-reference/rest/ImageBytes) | | \[optional] | | **description** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] \[default to 'private'] | ### Return type [**DeferredTaskExecutionResponseSchema**](/api-reference/rest/DeferredTaskExecutionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/x-www-form-urlencoded * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_create\_asset\_with\_urdf** > src\_app\_api\_assets\_create\_asset\_with\_urdf(asset\_create\_with\_urdf\_schema) Create Asset With Urdf ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_create_with_urdf_schema import AssetCreateWithURDFSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) asset_create_with_urdf_schema = cyberwave.rest.AssetCreateWithURDFSchema() # AssetCreateWithURDFSchema | try: # Create Asset With Urdf api_instance.src_app_api_assets_create_asset_with_urdf(asset_create_with_urdf_schema) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_create_asset_with_urdf: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **asset\_create\_with\_urdf\_schema** | [**AssetCreateWithURDFSchema**](/api-reference/rest/AssetCreateWithURDFSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_delete\_asset** > src\_app\_api\_assets\_delete\_asset(uuid) Delete Asset ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Asset api_instance.src_app_api_assets_delete_asset(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_delete_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_export\_asset** > src\_app\_api\_assets\_export\_asset(uuid) Export Asset Export an asset as a .cbw package (zip file). The .cbw package contains all asset data including: * Asset metadata, capabilities, and kinematics * GLB visualization file (if present) * Thumbnail (if present) * URDF project files (if present) * Attachments (if present) This endpoint supports both authenticated and anonymous access for public assets. ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Export Asset api_instance.src_app_api_assets_export_asset(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_export_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_asset** > AssetSchema src\_app\_api\_assets\_get\_asset(uuid) Get Asset Get an asset by UUID or registry\_id. Supports both authenticated and anonymous access (for public assets). ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Asset api_response = api_instance.src_app_api_assets_get_asset(uuid) print("The response of DefaultApi->src_app_api_assets_get_asset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_asset\_controllers** > List\[ControllerPolicySchema] src\_app\_api\_assets\_get\_asset\_controllers(uuid) Get Asset Controllers ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_schema import ControllerPolicySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Asset Controllers api_response = api_instance.src_app_api_assets_get_asset_controllers(uuid) print("The response of DefaultApi->src_app_api_assets_get_asset_controllers:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_asset_controllers: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[ControllerPolicySchema\]**](/api-reference/rest/ControllerPolicySchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_asset\_kinematics** > Dict\[str, object] src\_app\_api\_assets\_get\_asset\_kinematics(uuid) Get Asset Kinematics Get asset kinematics by UUID or registry\_id. Supports both authenticated and anonymous access (for public assets). ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Asset Kinematics api_response = api_instance.src_app_api_assets_get_asset_kinematics(uuid) print("The response of DefaultApi->src_app_api_assets_get_asset_kinematics:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_asset_kinematics: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_asset\_universal\_schema** > Dict\[str, object] src\_app\_api\_assets\_get\_asset\_universal\_schema(uuid) Get Asset Universal Schema Get the asset's universal schema as JSON (for download). Supports both authenticated and anonymous access (for public assets). ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Asset Universal Schema api_response = api_instance.src_app_api_assets_get_asset_universal_schema(uuid) print("The response of DefaultApi->src_app_api_assets_get_asset_universal_schema:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_asset_universal_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_asset\_universal\_schema\_at\_path** > Dict\[str, object] src\_app\_api\_assets\_get\_asset\_universal\_schema\_at\_path(uuid, path=path) Get Asset Universal Schema At Path Get value at a specific JSON Pointer path in the asset's universal schema. Supports both authenticated and anonymous access (for public assets). Query params: path: JSON Pointer path (e.g., /sensors/0, /extensions/cyberwave/capabilities) Returns: `{"path": "...", "value": }` ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | path = '' # str | (optional) (default to '') try: # Get Asset Universal Schema At Path api_response = api_instance.src_app_api_assets_get_asset_universal_schema_at_path(uuid, path=path) print("The response of DefaultApi->src_app_api_assets_get_asset_universal_schema_at_path:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_asset_universal_schema_at_path: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | | | **path** | **str** | | \[optional] \[default to ''] | ### Return type **Dict\[str, object]** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_popular\_tags** > PopularTagsResponseSchema src\_app\_api\_assets\_get\_popular\_tags() Get Popular Tags Get the most popular tags from asset metadata. Results are cached for 1 hour for performance. ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.popular_tags_response_schema import PopularTagsResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Popular Tags api_response = api_instance.src_app_api_assets_get_popular_tags() print("The response of DefaultApi->src_app_api_assets_get_popular_tags:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_popular_tags: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**PopularTagsResponseSchema**](/api-reference/rest/PopularTagsResponseSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_get\_public\_vendors** > List\[Optional\[str]] src\_app\_api\_assets\_get\_public\_vendors() Get Public Vendors Get the list of vendors that have public assets. Used by frontend to whitelist vendor pages for unauthenticated access. Results are cached for 1 hour for performance. ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Public Vendors api_response = api_instance.src_app_api_assets_get_public_vendors() print("The response of DefaultApi->src_app_api_assets_get_public_vendors:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_get_public_vendors: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type **List\[Optional\[str]]** ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_import\_asset\_package** > AssetSchema src\_app\_api\_assets\_import\_asset\_package(file, workspace\_uuid=workspace\_uuid, custom\_registry\_id=custom\_registry\_id) Import Asset Package Import an asset from a .cbw package file. The .cbw package should be a zip file created by the export endpoint, containing manifest.json, asset.json, and associated files. This allows transferring assets between Cyberwave instances. Parameters: file: The .cbw file to import workspace\_uuid: Optional target workspace UUID. If not provided, uses user's first workspace. custom\_registry\_id: Optional custom registry ID for the imported asset. If not provided, uses the original registry\_id from the package. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) file = None # bytearray | workspace_uuid = 'workspace_uuid_example' # str | (optional) custom_registry_id = 'custom_registry_id_example' # str | (optional) try: # Import Asset Package api_response = api_instance.src_app_api_assets_import_asset_package(file, workspace_uuid=workspace_uuid, custom_registry_id=custom_registry_id) print("The response of DefaultApi->src_app_api_assets_import_asset_package:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_import_asset_package: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------- | ----------- | ----------- | | **file** | **bytearray** | | | | **workspace\_uuid** | **str** | | \[optional] | | **custom\_registry\_id** | **str** | | \[optional] | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_import\_catalog\_asset** > AssetSchema src\_app\_api\_assets\_import\_catalog\_asset(asset\_catalog\_import\_schema) Import Catalog Asset ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_catalog_import_schema import AssetCatalogImportSchema from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) asset_catalog_import_schema = cyberwave.rest.AssetCatalogImportSchema() # AssetCatalogImportSchema | try: # Import Catalog Asset api_response = api_instance.src_app_api_assets_import_catalog_asset(asset_catalog_import_schema) print("The response of DefaultApi->src_app_api_assets_import_catalog_asset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_import_catalog_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **asset\_catalog\_import\_schema** | [**AssetCatalogImportSchema**](/api-reference/rest/AssetCatalogImportSchema) | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_initiate\_large\_glb\_upload** > InitiateLargeUploadResponse src\_app\_api\_assets\_initiate\_large\_glb\_upload(uuid, initiate\_large\_upload\_schema) Initiate Large Glb Upload Initiate a large GLB file upload for an asset using Google Cloud signed URLs. This endpoint supports GLB files larger than 32MB. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.initiate_large_upload_response import InitiateLargeUploadResponse from cyberwave.rest.models.initiate_large_upload_schema import InitiateLargeUploadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | initiate_large_upload_schema = cyberwave.rest.InitiateLargeUploadSchema() # InitiateLargeUploadSchema | try: # Initiate Large Glb Upload api_response = api_instance.src_app_api_assets_initiate_large_glb_upload(uuid, initiate_large_upload_schema) print("The response of DefaultApi->src_app_api_assets_initiate_large_glb_upload:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_initiate_large_glb_upload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **initiate\_large\_upload\_schema** | [**InitiateLargeUploadSchema**](/api-reference/rest/InitiateLargeUploadSchema) | | | ### Return type [**InitiateLargeUploadResponse**](/api-reference/rest/InitiateLargeUploadResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_list\_assets** > List\[AssetListSchema] src\_app\_api\_assets\_list\_assets() List Assets ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_list_schema import AssetListSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Assets api_response = api_instance.src_app_api_assets_list_assets() print("The response of DefaultApi->src_app_api_assets_list_assets:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_list_assets: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[AssetListSchema\]**](/api-reference/rest/AssetListSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_llm\_generation** > LLMResponseSchema src\_app\_api\_assets\_llm\_generation(uuid, llm\_generation\_schema) Llm Generation ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.llm_generation_schema import LLMGenerationSchema from cyberwave.rest.models.llm_response_schema import LLMResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | llm_generation_schema = cyberwave.rest.LLMGenerationSchema() # LLMGenerationSchema | try: # Llm Generation api_response = api_instance.src_app_api_assets_llm_generation(uuid, llm_generation_schema) print("The response of DefaultApi->src_app_api_assets_llm_generation:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_llm_generation: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **llm\_generation\_schema** | [**LLMGenerationSchema**](/api-reference/rest/LLMGenerationSchema) | | | ### Return type [**LLMResponseSchema**](/api-reference/rest/LLMResponseSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_patch\_asset\_universal\_schema** > Dict\[str, object] src\_app\_api\_assets\_patch\_asset\_universal\_schema(uuid, universal\_schema\_patch\_schema) Patch Asset Universal Schema Update the asset's universal schema using JSON Pointer operations. This allows editing the asset schema, including: * /sensors (array of sensor objects) * /extensions/cyberwave/capabilities * /links, /joints, /actuators, etc. When capabilities are patched, they are validated using CapabilitiesValidator. Body: ```json theme={null} { "op": "add" | "replace", "path": "/sensors/0/parameters/id", "value": "my_camera" } ``` Returns: ```json theme={null} { "schema": "", "updated": { "op": "...", "path": "..." } } ``` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.universal_schema_patch_schema import UniversalSchemaPatchSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | universal_schema_patch_schema = cyberwave.rest.UniversalSchemaPatchSchema() # UniversalSchemaPatchSchema | try: # Patch Asset Universal Schema api_response = api_instance.src_app_api_assets_patch_asset_universal_schema(uuid, universal_schema_patch_schema) print("The response of DefaultApi->src_app_api_assets_patch_asset_universal_schema:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_patch_asset_universal_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------ | -------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **universal\_schema\_patch\_schema** | [**UniversalSchemaPatchSchema**](/api-reference/rest/UniversalSchemaPatchSchema) | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_rebuild\_asset\_universal\_schema** > Dict\[str, object] src\_app\_api\_assets\_rebuild\_asset\_universal\_schema(uuid, sync=sync) Rebuild Asset Universal Schema Trigger regeneration of an Asset's universal\_schema from its URDFProject. By default, queues a Celery task and returns immediately. Pass `?sync=true` to execute synchronously and block until complete (useful for local testing). Returns: ``` { "queued": bool, "asset_uuid": "...", "urdf_project_uuid": "...", } ``` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | sync = False # bool | (optional) (default to False) try: # Rebuild Asset Universal Schema api_response = api_instance.src_app_api_assets_rebuild_asset_universal_schema(uuid, sync=sync) print("The response of DefaultApi->src_app_api_assets_rebuild_asset_universal_schema:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_rebuild_asset_universal_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | -------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **sync** | **bool** | | \[optional] \[default to False] | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_set\_glb\_from\_attachment** > AssetSchema src\_app\_api\_assets\_set\_glb\_from\_attachment(uuid, asset\_glb\_from\_attachment\_schema) Set Glb From Attachment Set an asset's GLB file from an existing attachment. This is useful for processing workflows where an uploaded attachment gets converted/processed into the main GLB visualization file. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_glb_from_attachment_schema import AssetGLBFromAttachmentSchema from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | asset_glb_from_attachment_schema = cyberwave.rest.AssetGLBFromAttachmentSchema() # AssetGLBFromAttachmentSchema | try: # Set Glb From Attachment api_response = api_instance.src_app_api_assets_set_glb_from_attachment(uuid, asset_glb_from_attachment_schema) print("The response of DefaultApi->src_app_api_assets_set_glb_from_attachment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_set_glb_from_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------------- | ------------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **asset\_glb\_from\_attachment\_schema** | [**AssetGLBFromAttachmentSchema**](/api-reference/rest/AssetGLBFromAttachmentSchema) | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_update\_asset** > AssetSchema src\_app\_api\_assets\_update\_asset(uuid, asset\_update\_schema) Update Asset Update an asset by UUID or registry\_id. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.models.asset_update_schema import AssetUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | asset_update_schema = cyberwave.rest.AssetUpdateSchema() # AssetUpdateSchema | try: # Update Asset api_response = api_instance.src_app_api_assets_update_asset(uuid, asset_update_schema) print("The response of DefaultApi->src_app_api_assets_update_asset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_update_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **asset\_update\_schema** | [**AssetUpdateSchema**](/api-reference/rest/AssetUpdateSchema) | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_upload\_glb** > AssetSchema src\_app\_api\_assets\_upload\_glb(uuid, file) Upload Glb ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | try: # Upload Glb api_response = api_instance.src_app_api_assets_upload_glb(uuid, file) print("The response of DefaultApi->src_app_api_assets_upload_glb:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_upload_glb: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------------- | ----------- | ----- | | **uuid** | **str** | | | | **file** | **bytearray** | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_upload\_thumbnail\_file** > AssetSchema src\_app\_api\_assets\_upload\_thumbnail\_file(uuid, file) Upload Thumbnail File ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.asset_schema import AssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | try: # Upload Thumbnail File api_response = api_instance.src_app_api_assets_upload_thumbnail_file(uuid, file) print("The response of DefaultApi->src_app_api_assets_upload_thumbnail_file:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_upload_thumbnail_file: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------------- | ----------- | ----- | | **uuid** | **str** | | | | **file** | **bytearray** | | | ### Return type [**AssetSchema**](/api-reference/rest/AssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_assets\_vlm\_generation** > VLMResponseSchema src\_app\_api\_assets\_vlm\_generation(uuid, vlm\_generation\_schema) Vlm Generation Generate a response using a Vision Language Model (VLM) with the given prompt and image. This endpoint uses Google's Gemini 3 Pro vision model to analyze images and generate text responses based on the provided prompt. Args: request: The HTTP request uuid: The asset UUID (currently unused but kept for API consistency) payload: Contains the prompt and image\_url to analyze Returns: VLMResponseSchema with the model's text response ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.vlm_generation_schema import VLMGenerationSchema from cyberwave.rest.models.vlm_response_schema import VLMResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | vlm_generation_schema = cyberwave.rest.VLMGenerationSchema() # VLMGenerationSchema | try: # Vlm Generation api_response = api_instance.src_app_api_assets_vlm_generation(uuid, vlm_generation_schema) print("The response of DefaultApi->src_app_api_assets_vlm_generation:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_assets_vlm_generation: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **vlm\_generation\_schema** | [**VLMGenerationSchema**](/api-reference/rest/VLMGenerationSchema) | | | ### Return type [**VLMResponseSchema**](/api-reference/rest/VLMResponseSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_complete\_large\_attachment\_upload** > AttachmentSchema src\_app\_api\_attachments\_complete\_large\_attachment\_upload(uuid, complete\_large\_upload\_schema) Complete Large Attachment Upload Complete a large file upload for an attachment. This marks the uploaded file as the attachment's file. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.attachment_schema import AttachmentSchema from cyberwave.rest.models.complete_large_upload_schema import CompleteLargeUploadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | complete_large_upload_schema = cyberwave.rest.CompleteLargeUploadSchema() # CompleteLargeUploadSchema | try: # Complete Large Attachment Upload api_response = api_instance.src_app_api_attachments_complete_large_attachment_upload(uuid, complete_large_upload_schema) print("The response of DefaultApi->src_app_api_attachments_complete_large_attachment_upload:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_complete_large_attachment_upload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **complete\_large\_upload\_schema** | [**CompleteLargeUploadSchema**](/api-reference/rest/CompleteLargeUploadSchema) | | | ### Return type [**AttachmentSchema**](/api-reference/rest/AttachmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_create\_attachment** > AttachmentSchema src\_app\_api\_attachments\_create\_attachment(attachment\_create\_schema) Create Attachment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.attachment_create_schema import AttachmentCreateSchema from cyberwave.rest.models.attachment_schema import AttachmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) attachment_create_schema = cyberwave.rest.AttachmentCreateSchema() # AttachmentCreateSchema | try: # Create Attachment api_response = api_instance.src_app_api_attachments_create_attachment(attachment_create_schema) print("The response of DefaultApi->src_app_api_attachments_create_attachment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_create_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------ | ------------------------------------------------------------------------ | ----------- | ----- | | **attachment\_create\_schema** | [**AttachmentCreateSchema**](/api-reference/rest/AttachmentCreateSchema) | | | ### Return type [**AttachmentSchema**](/api-reference/rest/AttachmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_delete\_attachment** > src\_app\_api\_attachments\_delete\_attachment(uuid) Delete Attachment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Attachment api_instance.src_app_api_attachments_delete_attachment(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_delete_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_download\_attachment** > src\_app\_api\_attachments\_download\_attachment(uuid) Download Attachment Download attachment file content. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Download Attachment api_instance.src_app_api_attachments_download_attachment(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_download_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_get\_attachment** > AttachmentSchema src\_app\_api\_attachments\_get\_attachment(uuid) Get Attachment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.attachment_schema import AttachmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Attachment api_response = api_instance.src_app_api_attachments_get_attachment(uuid) print("The response of DefaultApi->src_app_api_attachments_get_attachment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_get_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**AttachmentSchema**](/api-reference/rest/AttachmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_initiate\_large\_attachment\_upload** > InitiateLargeUploadResponse src\_app\_api\_attachments\_initiate\_large\_attachment\_upload(uuid, initiate\_large\_upload\_schema) Initiate Large Attachment Upload Initiate a large file upload for an attachment using Google Cloud signed URLs. This endpoint supports files larger than 32MB. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.initiate_large_upload_response import InitiateLargeUploadResponse from cyberwave.rest.models.initiate_large_upload_schema import InitiateLargeUploadSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | initiate_large_upload_schema = cyberwave.rest.InitiateLargeUploadSchema() # InitiateLargeUploadSchema | try: # Initiate Large Attachment Upload api_response = api_instance.src_app_api_attachments_initiate_large_attachment_upload(uuid, initiate_large_upload_schema) print("The response of DefaultApi->src_app_api_attachments_initiate_large_attachment_upload:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_initiate_large_attachment_upload: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **initiate\_large\_upload\_schema** | [**InitiateLargeUploadSchema**](/api-reference/rest/InitiateLargeUploadSchema) | | | ### Return type [**InitiateLargeUploadResponse**](/api-reference/rest/InitiateLargeUploadResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_list\_attachments** > List\[AttachmentSchema] src\_app\_api\_attachments\_list\_attachments() List Attachments ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.attachment_schema import AttachmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Attachments api_response = api_instance.src_app_api_attachments_list_attachments() print("The response of DefaultApi->src_app_api_attachments_list_attachments:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_list_attachments: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[AttachmentSchema\]**](/api-reference/rest/AttachmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_update\_attachment** > AttachmentSchema src\_app\_api\_attachments\_update\_attachment(uuid, attachment\_create\_schema) Update Attachment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.attachment_create_schema import AttachmentCreateSchema from cyberwave.rest.models.attachment_schema import AttachmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | attachment_create_schema = cyberwave.rest.AttachmentCreateSchema() # AttachmentCreateSchema | try: # Update Attachment api_response = api_instance.src_app_api_attachments_update_attachment(uuid, attachment_create_schema) print("The response of DefaultApi->src_app_api_attachments_update_attachment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_update_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------ | ------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **attachment\_create\_schema** | [**AttachmentCreateSchema**](/api-reference/rest/AttachmentCreateSchema) | | | ### Return type [**AttachmentSchema**](/api-reference/rest/AttachmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_attachments\_upload\_attachment** > AttachmentSchema src\_app\_api\_attachments\_upload\_attachment(uuid, file) Upload Attachment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.attachment_schema import AttachmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | try: # Upload Attachment api_response = api_instance.src_app_api_attachments_upload_attachment(uuid, file) print("The response of DefaultApi->src_app_api_attachments_upload_attachment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_attachments_upload_attachment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------------- | ----------- | ----- | | **uuid** | **str** | | | | **file** | **bytearray** | | | ### Return type [**AttachmentSchema**](/api-reference/rest/AttachmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_clone\_controller\_policy** > ControllerPolicySchema src\_app\_api\_controller\_policies\_clone\_controller\_policy(uuid, workspace\_uuid=workspace\_uuid) Clone Controller Policy Clone a controller policy into the specified workspace (or user's default workspace). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_schema import ControllerPolicySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workspace_uuid = 'workspace_uuid_example' # str | (optional) try: # Clone Controller Policy api_response = api_instance.src_app_api_controller_policies_clone_controller_policy(uuid, workspace_uuid=workspace_uuid) print("The response of DefaultApi->src_app_api_controller_policies_clone_controller_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_clone_controller_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **uuid** | **str** | | | | **workspace\_uuid** | **str** | | \[optional] | ### Return type [**ControllerPolicySchema**](/api-reference/rest/ControllerPolicySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_create\_controller\_policy** > ControllerPolicySchema src\_app\_api\_controller\_policies\_create\_controller\_policy(controller\_policy\_create\_schema) Create Controller Policy Create a new controller policy. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_create_schema import ControllerPolicyCreateSchema from cyberwave.rest.models.controller_policy_schema import ControllerPolicySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) controller_policy_create_schema = cyberwave.rest.ControllerPolicyCreateSchema() # ControllerPolicyCreateSchema | try: # Create Controller Policy api_response = api_instance.src_app_api_controller_policies_create_controller_policy(controller_policy_create_schema) print("The response of DefaultApi->src_app_api_controller_policies_create_controller_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_create_controller_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------------- | ------------------------------------------------------------------------------------ | ----------- | ----- | | **controller\_policy\_create\_schema** | [**ControllerPolicyCreateSchema**](/api-reference/rest/ControllerPolicyCreateSchema) | | | ### Return type [**ControllerPolicySchema**](/api-reference/rest/ControllerPolicySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_delete\_controller\_policy** > Dict\[str, Optional\[bool]] src\_app\_api\_controller\_policies\_delete\_controller\_policy(uuid) Delete Controller Policy Delete a controller policy. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Controller Policy api_response = api_instance.src_app_api_controller_policies_delete_controller_policy(uuid) print("The response of DefaultApi->src_app_api_controller_policies_delete_controller_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_delete_controller_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, Optional\[bool]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_execute\_controller\_policy** > ControllerPolicyExecuteResponseSchema src\_app\_api\_controller\_policies\_execute\_controller\_policy(uuid, controller\_policy\_execute\_schema) Execute Controller Policy ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_execute_response_schema import ControllerPolicyExecuteResponseSchema from cyberwave.rest.models.controller_policy_execute_schema import ControllerPolicyExecuteSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | controller_policy_execute_schema = cyberwave.rest.ControllerPolicyExecuteSchema() # ControllerPolicyExecuteSchema | try: # Execute Controller Policy api_response = api_instance.src_app_api_controller_policies_execute_controller_policy(uuid, controller_policy_execute_schema) print("The response of DefaultApi->src_app_api_controller_policies_execute_controller_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_execute_controller_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **controller\_policy\_execute\_schema** | [**ControllerPolicyExecuteSchema**](/api-reference/rest/ControllerPolicyExecuteSchema) | | | ### Return type [**ControllerPolicyExecuteResponseSchema**](/api-reference/rest/ControllerPolicyExecuteResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_get\_action\_from\_policy** > str src\_app\_api\_controller\_policies\_get\_action\_from\_policy(uuid, instruction, twin\_uuid, camera\_twin\_uuid) Get Action From Policy Get action from an ML model policy based on instruction and twin state. Validates that the twins exist and the camera is live, then dispatches the actual execution to a Celery worker. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | instruction = 'instruction_example' # str | twin_uuid = 'twin_uuid_example' # str | camera_twin_uuid = 'camera_twin_uuid_example' # str | try: # Get Action From Policy api_response = api_instance.src_app_api_controller_policies_get_action_from_policy(uuid, instruction, twin_uuid, camera_twin_uuid) print("The response of DefaultApi->src_app_api_controller_policies_get_action_from_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_get_action_from_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **instruction** | **str** | | | | **twin\_uuid** | **str** | | | | **camera\_twin\_uuid** | **str** | | | ### Return type **str** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_get\_controller\_policy** > ControllerPolicySchema src\_app\_api\_controller\_policies\_get\_controller\_policy(uuid) Get Controller Policy Get a specific controller policy by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_schema import ControllerPolicySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Controller Policy api_response = api_instance.src_app_api_controller_policies_get_controller_policy(uuid) print("The response of DefaultApi->src_app_api_controller_policies_get_controller_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_get_controller_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**ControllerPolicySchema**](/api-reference/rest/ControllerPolicySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_list\_controller\_policies** > List\[ControllerPolicySchema] src\_app\_api\_controller\_policies\_list\_controller\_policies(asset\_uuid=asset\_uuid, workspace\_uuid=workspace\_uuid) List Controller Policies List all controller policies visible to the authenticated user, optionally filtered by asset and workspace. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_schema import ControllerPolicySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) asset_uuid = 'asset_uuid_example' # str | (optional) workspace_uuid = 'workspace_uuid_example' # str | (optional) try: # List Controller Policies api_response = api_instance.src_app_api_controller_policies_list_controller_policies(asset_uuid=asset_uuid, workspace_uuid=workspace_uuid) print("The response of DefaultApi->src_app_api_controller_policies_list_controller_policies:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_list_controller_policies: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **asset\_uuid** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | ### Return type [**List\[ControllerPolicySchema\]**](/api-reference/rest/ControllerPolicySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_controller\_policies\_update\_controller\_policy** > ControllerPolicySchema src\_app\_api\_controller\_policies\_update\_controller\_policy(uuid, controller\_policy\_update\_schema) Update Controller Policy Update an existing controller policy. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.controller_policy_schema import ControllerPolicySchema from cyberwave.rest.models.controller_policy_update_schema import ControllerPolicyUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | controller_policy_update_schema = cyberwave.rest.ControllerPolicyUpdateSchema() # ControllerPolicyUpdateSchema | try: # Update Controller Policy api_response = api_instance.src_app_api_controller_policies_update_controller_policy(uuid, controller_policy_update_schema) print("The response of DefaultApi->src_app_api_controller_policies_update_controller_policy:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_controller_policies_update_controller_policy: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------------- | ------------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **controller\_policy\_update\_schema** | [**ControllerPolicyUpdateSchema**](/api-reference/rest/ControllerPolicyUpdateSchema) | | | ### Return type [**ControllerPolicySchema**](/api-reference/rest/ControllerPolicySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_create\_dataset** > Dict\[str, object] src\_app\_api\_datasets\_create\_dataset(dataset\_create\_schema) Create Dataset Create a new dataset. This starts an async task to generate the parquet file. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.dataset_create_schema import DatasetCreateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) dataset_create_schema = cyberwave.rest.DatasetCreateSchema() # DatasetCreateSchema | try: # Create Dataset api_response = api_instance.src_app_api_datasets_create_dataset(dataset_create_schema) print("The response of DefaultApi->src_app_api_datasets_create_dataset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_create_dataset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **dataset\_create\_schema** | [**DatasetCreateSchema**](/api-reference/rest/DatasetCreateSchema) | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_delete\_dataset** > Dict\[str, Optional\[bool]] src\_app\_api\_datasets\_delete\_dataset(uuid) Delete Dataset Soft delete a dataset by setting is\_deleted=True. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Dataset api_response = api_instance.src_app_api_datasets_delete_dataset(uuid) print("The response of DefaultApi->src_app_api_datasets_delete_dataset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_delete_dataset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, Optional\[bool]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_get\_dataset** > DatasetSchema src\_app\_api\_datasets\_get\_dataset(uuid) Get Dataset Get a specific dataset by UUID. Generates signed URL for dataset parquet file if available. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.dataset_schema import DatasetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Dataset api_response = api_instance.src_app_api_datasets_get_dataset(uuid) print("The response of DefaultApi->src_app_api_datasets_get_dataset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_get_dataset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**DatasetSchema**](/api-reference/rest/DatasetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_get\_dataset\_zip\_url** > DatasetZipUrlSchema src\_app\_api\_datasets\_get\_dataset\_zip\_url(uuid) Get Dataset Zip Url Get a signed URL for the dataset zip file. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.dataset_zip_url_schema import DatasetZipUrlSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Dataset Zip Url api_response = api_instance.src_app_api_datasets_get_dataset_zip_url(uuid) print("The response of DefaultApi->src_app_api_datasets_get_dataset_zip_url:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_get_dataset_zip_url: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**DatasetZipUrlSchema**](/api-reference/rest/DatasetZipUrlSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_list\_datasets** > List\[DatasetSchema] src\_app\_api\_datasets\_list\_datasets() List Datasets List all datasets visible to the current user that are not deleted. Generates signed URLs for dataset parquet files. Query parameters: environment: Optional UUID to filter datasets by environment (filters datasets whose episodes contain twins from that environment). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.dataset_schema import DatasetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Datasets api_response = api_instance.src_app_api_datasets_list_datasets() print("The response of DefaultApi->src_app_api_datasets_list_datasets:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_list_datasets: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[DatasetSchema\]**](/api-reference/rest/DatasetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_remove\_episode\_from\_dataset** > DatasetSchema src\_app\_api\_datasets\_remove\_episode\_from\_dataset(uuid, episode\_uuid) Remove Episode From Dataset Remove a single episode from a dataset. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.dataset_schema import DatasetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | episode_uuid = 'episode_uuid_example' # str | try: # Remove Episode From Dataset api_response = api_instance.src_app_api_datasets_remove_episode_from_dataset(uuid, episode_uuid) print("The response of DefaultApi->src_app_api_datasets_remove_episode_from_dataset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_remove_episode_from_dataset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **episode\_uuid** | **str** | | | ### Return type [**DatasetSchema**](/api-reference/rest/DatasetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_datasets\_update\_dataset** > DatasetSchema src\_app\_api\_datasets\_update\_dataset(uuid, dataset\_update\_schema) Update Dataset Update a dataset. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.dataset_schema import DatasetSchema from cyberwave.rest.models.dataset_update_schema import DatasetUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | dataset_update_schema = cyberwave.rest.DatasetUpdateSchema() # DatasetUpdateSchema | try: # Update Dataset api_response = api_instance.src_app_api_datasets_update_dataset(uuid, dataset_update_schema) print("The response of DefaultApi->src_app_api_datasets_update_dataset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_datasets_update_dataset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **dataset\_update\_schema** | [**DatasetUpdateSchema**](/api-reference/rest/DatasetUpdateSchema) | | | ### Return type [**DatasetSchema**](/api-reference/rest/DatasetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edge\_nodes\_discover\_twins** > DiscoveryResponseSchema src\_app\_api\_edge\_nodes\_discover\_twins(edge\_register\_schema) Discover Twins Discover all twins this edge device should serve. This endpoint auto-registers the edge if it does not exist and returns all twins that contain this edge fingerprint in Twin.metadata\["edge\_fingerprint"]. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.discovery_response_schema import DiscoveryResponseSchema from cyberwave.rest.models.edge_register_schema import EdgeRegisterSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) edge_register_schema = cyberwave.rest.EdgeRegisterSchema() # EdgeRegisterSchema | try: # Discover Twins api_response = api_instance.src_app_api_edge_nodes_discover_twins(edge_register_schema) print("The response of DefaultApi->src_app_api_edge_nodes_discover_twins:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edge_nodes_discover_twins: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------- | ---------------------------------------------------------------- | ----------- | ----- | | **edge\_register\_schema** | [**EdgeRegisterSchema**](/api-reference/rest/EdgeRegisterSchema) | | | ### Return type [**DiscoveryResponseSchema**](/api-reference/rest/DiscoveryResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edge\_nodes\_get\_edge\_twins** > List\[TwinBindingSchema] src\_app\_api\_edge\_nodes\_get\_edge\_twins(uuid) Get Edge Twins Get all twins bound to an edge. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_binding_schema import TwinBindingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Edge Twins api_response = api_instance.src_app_api_edge_nodes_get_edge_twins(uuid) print("The response of DefaultApi->src_app_api_edge_nodes_get_edge_twins:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edge_nodes_get_edge_twins: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[TwinBindingSchema\]**](/api-reference/rest/TwinBindingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edge\_nodes\_pair\_twin\_to\_edge** > TwinBindingSchema src\_app\_api\_edge\_nodes\_pair\_twin\_to\_edge(uuid, pair\_twin\_schema) Pair Twin To Edge Pair a twin to an edge. Pairing is persisted in twin metadata: * metadata\["edge\_fingerprint"] for identity/binding * metadata\["edge\_configs"] for runtime camera config ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.pair_twin_schema import PairTwinSchema from cyberwave.rest.models.twin_binding_schema import TwinBindingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | pair_twin_schema = cyberwave.rest.PairTwinSchema() # PairTwinSchema | try: # Pair Twin To Edge api_response = api_instance.src_app_api_edge_nodes_pair_twin_to_edge(uuid, pair_twin_schema) print("The response of DefaultApi->src_app_api_edge_nodes_pair_twin_to_edge:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edge_nodes_pair_twin_to_edge: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------- | -------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **pair\_twin\_schema** | [**PairTwinSchema**](/api-reference/rest/PairTwinSchema) | | | ### Return type [**TwinBindingSchema**](/api-reference/rest/TwinBindingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edge\_nodes\_restart\_edge\_core** > EdgeCoreRestartResponseSchema src\_app\_api\_edge\_nodes\_restart\_edge\_core(uuid) Restart Edge Core Publish an MQTT restart command for the target edge-core instance. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.edge_core_restart_response_schema import EdgeCoreRestartResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Restart Edge Core api_response = api_instance.src_app_api_edge_nodes_restart_edge_core(uuid) print("The response of DefaultApi->src_app_api_edge_nodes_restart_edge_core:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edge_nodes_restart_edge_core: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**EdgeCoreRestartResponseSchema**](/api-reference/rest/EdgeCoreRestartResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edge\_nodes\_unpair\_twin\_from\_edge** > src\_app\_api\_edge\_nodes\_unpair\_twin\_from\_edge(uuid, twin\_uuid) Unpair Twin From Edge Remove a twin binding from an edge. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_uuid = 'twin_uuid_example' # str | try: # Unpair Twin From Edge api_instance.src_app_api_edge_nodes_unpair_twin_from_edge(uuid, twin_uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edge_nodes_unpair_twin_from_edge: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edge\_nodes\_update\_camera\_config** > src\_app\_api\_edge\_nodes\_update\_camera\_config(uuid, twin\_uuid, camera\_config\_update\_schema) Update Camera Config DEPRECATED: camera configs now live in Twin.metadata\["edge\_configs"] and must be updated via twin metadata writes. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.camera_config_update_schema import CameraConfigUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_uuid = 'twin_uuid_example' # str | camera_config_update_schema = cyberwave.rest.CameraConfigUpdateSchema() # CameraConfigUpdateSchema | try: # Update Camera Config api_instance.src_app_api_edge_nodes_update_camera_config(uuid, twin_uuid, camera_config_update_schema) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edge_nodes_update_camera_config: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_uuid** | **str** | | | | **camera\_config\_update\_schema** | [**CameraConfigUpdateSchema**](/api-reference/rest/CameraConfigUpdateSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edges\_create\_edge** > EdgeSchema src\_app\_api\_edges\_create\_edge(edge\_create\_schema) Create Edge ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.edge_create_schema import EdgeCreateSchema from cyberwave.rest.models.edge_schema import EdgeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) edge_create_schema = cyberwave.rest.EdgeCreateSchema() # EdgeCreateSchema | try: # Create Edge api_response = api_instance.src_app_api_edges_create_edge(edge_create_schema) print("The response of DefaultApi->src_app_api_edges_create_edge:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edges_create_edge: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------------------------------------------------------ | ----------- | ----- | | **edge\_create\_schema** | [**EdgeCreateSchema**](/api-reference/rest/EdgeCreateSchema) | | | ### Return type [**EdgeSchema**](/api-reference/rest/EdgeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edges\_delete\_edge** > src\_app\_api\_edges\_delete\_edge(uuid) Delete Edge ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Edge api_instance.src_app_api_edges_delete_edge(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edges_delete_edge: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edges\_get\_edge** > EdgeSchema src\_app\_api\_edges\_get\_edge(uuid) Get Edge ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.edge_schema import EdgeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Edge api_response = api_instance.src_app_api_edges_get_edge(uuid) print("The response of DefaultApi->src_app_api_edges_get_edge:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edges_get_edge: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**EdgeSchema**](/api-reference/rest/EdgeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edges\_get\_edges** > List\[EdgeSchema] src\_app\_api\_edges\_get\_edges() Get Edges ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.edge_schema import EdgeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Edges api_response = api_instance.src_app_api_edges_get_edges() print("The response of DefaultApi->src_app_api_edges_get_edges:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edges_get_edges: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[EdgeSchema\]**](/api-reference/rest/EdgeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_edges\_update\_edge** > EdgeSchema src\_app\_api\_edges\_update\_edge(uuid, edge\_create\_schema) Update Edge ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.edge_create_schema import EdgeCreateSchema from cyberwave.rest.models.edge_schema import EdgeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | edge_create_schema = cyberwave.rest.EdgeCreateSchema() # EdgeCreateSchema | try: # Update Edge api_response = api_instance.src_app_api_edges_update_edge(uuid, edge_create_schema) print("The response of DefaultApi->src_app_api_edges_update_edge:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_edges_update_edge: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **edge\_create\_schema** | [**EdgeCreateSchema**](/api-reference/rest/EdgeCreateSchema) | | | ### Return type [**EdgeSchema**](/api-reference/rest/EdgeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_cancel\_environment\_invitation** > Dict\[str, object] src\_app\_api\_environments\_cancel\_environment\_invitation(invitation\_uuid) Cancel Environment Invitation Cancel a pending invitation ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) invitation_uuid = 'invitation_uuid_example' # str | try: # Cancel Environment Invitation api_response = api_instance.src_app_api_environments_cancel_environment_invitation(invitation_uuid) print("The response of DefaultApi->src_app_api_environments_cancel_environment_invitation:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_cancel_environment_invitation: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **invitation\_uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_create\_environment\_for\_project** > EnvironmentSchema src\_app\_api\_environments\_create\_environment\_for\_project(uuid, environment\_create\_schema) Create Environment For Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_create_schema import EnvironmentCreateSchema from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | environment_create_schema = cyberwave.rest.EnvironmentCreateSchema() # EnvironmentCreateSchema | try: # Create Environment For Project api_response = api_instance.src_app_api_environments_create_environment_for_project(uuid, environment_create_schema) print("The response of DefaultApi->src_app_api_environments_create_environment_for_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_create_environment_for_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **environment\_create\_schema** | [**EnvironmentCreateSchema**](/api-reference/rest/EnvironmentCreateSchema) | | | ### Return type [**EnvironmentSchema**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_create\_environment\_link** > Dict\[str, object] src\_app\_api\_environments\_create\_environment\_link(uuid) Create Environment Link Create a shareable link for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Create Environment Link api_response = api_instance.src_app_api_environments_create_environment_link(uuid) print("The response of DefaultApi->src_app_api_environments_create_environment_link:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_create_environment_link: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_create\_environment\_simulation** > Dict\[str, object] src\_app\_api\_environments\_create\_environment\_simulation(uuid, simulation\_start\_schema=simulation\_start\_schema) Create Environment Simulation ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.simulation_start_schema import SimulationStartSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | simulation_start_schema = cyberwave.rest.SimulationStartSchema() # SimulationStartSchema | (optional) try: # Create Environment Simulation api_response = api_instance.src_app_api_environments_create_environment_simulation(uuid, simulation_start_schema=simulation_start_schema) print("The response of DefaultApi->src_app_api_environments_create_environment_simulation:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_create_environment_simulation: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ---------------------------------------------------------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **simulation\_start\_schema** | [**SimulationStartSchema**](/api-reference/rest/SimulationStartSchema) | | \[optional] | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_create\_environment\_snapshot** > EnvironmentSnapshotSchema src\_app\_api\_environments\_create\_environment\_snapshot(uuid, environment\_snapshot\_create\_schema) Create Environment Snapshot Create a new environment snapshot ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_snapshot_create_schema import EnvironmentSnapshotCreateSchema from cyberwave.rest.models.environment_snapshot_schema import EnvironmentSnapshotSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | environment_snapshot_create_schema = cyberwave.rest.EnvironmentSnapshotCreateSchema() # EnvironmentSnapshotCreateSchema | try: # Create Environment Snapshot api_response = api_instance.src_app_api_environments_create_environment_snapshot(uuid, environment_snapshot_create_schema) print("The response of DefaultApi->src_app_api_environments_create_environment_snapshot:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_create_environment_snapshot: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------------- | ------------------------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **environment\_snapshot\_create\_schema** | [**EnvironmentSnapshotCreateSchema**](/api-reference/rest/EnvironmentSnapshotCreateSchema) | | | ### Return type [**EnvironmentSnapshotSchema**](/api-reference/rest/EnvironmentSnapshotSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_add\_environment\_waypoints** > EnvironmentWaypointSchema\[] src\_app\_api\_environments\_add\_environment\_waypoints(uuid, environment\_waypoint\_bulk\_create\_schema) Add Environment Waypoints Append multiple waypoints to an environment. ### Parameters | Name | Type | Description | Notes | | ----------------------------------------------- | -------------------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **environment\_waypoint\_bulk\_create\_schema** | [**EnvironmentWaypointBulkCreateSchema**](/api-reference/rest/EnvironmentWaypointBulkCreateSchema) | | | ### Return type [**EnvironmentWaypointSchema\[\]**](/api-reference/rest/EnvironmentWaypointSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_delete\_environment\_waypoint** > EnvironmentWaypointSchema\[] src\_app\_api\_environments\_delete\_environment\_waypoint(uuid, waypoint\_id) Delete Environment Waypoint Delete a waypoint from an environment. ### Parameters | Name | Type | Description | Notes | | ---------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **waypoint\_id** | **str** | | | ### Return type [**EnvironmentWaypointSchema\[\]**](/api-reference/rest/EnvironmentWaypointSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_waypoints** > EnvironmentWaypointSchema\[] src\_app\_api\_environments\_get\_environment\_waypoints(uuid) Get Environment Waypoints List environment waypoints. ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**EnvironmentWaypointSchema\[\]**](/api-reference/rest/EnvironmentWaypointSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_create\_standalone\_environment** > EnvironmentSchema src\_app\_api\_environments\_create\_standalone\_environment(environment\_create\_schema) Create Standalone Environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_create_schema import EnvironmentCreateSchema from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) environment_create_schema = cyberwave.rest.EnvironmentCreateSchema() # EnvironmentCreateSchema | try: # Create Standalone Environment api_response = api_instance.src_app_api_environments_create_standalone_environment(environment_create_schema) print("The response of DefaultApi->src_app_api_environments_create_standalone_environment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_create_standalone_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **environment\_create\_schema** | [**EnvironmentCreateSchema**](/api-reference/rest/EnvironmentCreateSchema) | | | ### Return type [**EnvironmentSchema**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_delete\_environment** > src\_app\_api\_environments\_delete\_environment(uuid) Delete Environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Environment api_instance.src_app_api_environments_delete_environment(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_delete_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_delete\_environment\_for\_project** > src\_app\_api\_environments\_delete\_environment\_for\_project(project\_uuid, uuid) Delete Environment For Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) project_uuid = 'project_uuid_example' # str | uuid = 'uuid_example' # str | try: # Delete Environment For Project api_instance.src_app_api_environments_delete_environment_for_project(project_uuid, uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_delete_environment_for_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **project\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_delete\_environment\_snapshot** > Dict\[str, object] src\_app\_api\_environments\_delete\_environment\_snapshot(uuid, snapshot\_uuid) Delete Environment Snapshot Delete a snapshot for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | snapshot_uuid = 'snapshot_uuid_example' # str | try: # Delete Environment Snapshot api_response = api_instance.src_app_api_environments_delete_environment_snapshot(uuid, snapshot_uuid) print("The response of DefaultApi->src_app_api_environments_delete_environment_snapshot:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_delete_environment_snapshot: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **uuid** | **str** | | | | **snapshot\_uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_delete\_recording** > Dict\[str, object] src\_app\_api\_environments\_delete\_recording(uuid, recording\_uuid) Delete Recording Delete a recording. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | recording_uuid = 'recording_uuid_example' # str | try: # Delete Recording api_response = api_instance.src_app_api_environments_delete_recording(uuid, recording_uuid) print("The response of DefaultApi->src_app_api_environments_delete_recording:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_delete_recording: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **recording\_uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_generate\_telemetry\_recording** > RecordingGenerationResponseSchema src\_app\_api\_environments\_generate\_telemetry\_recording(uuid, payload) Generate Telemetry Recording Generate a Parquet recording containing telemetry data for a specific session. Payload should contain: * twin\_uuid: UUID of the twin * start\_timestamp: Start timestamp of the session (microseconds) * end\_timestamp: End timestamp of the session (microseconds) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.payload import Payload from cyberwave.rest.models.recording_generation_response_schema import RecordingGenerationResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | payload = cyberwave.rest.Payload() # Payload | try: # Generate Telemetry Recording api_response = api_instance.src_app_api_environments_generate_telemetry_recording(uuid, payload) print("The response of DefaultApi->src_app_api_environments_generate_telemetry_recording:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_generate_telemetry_recording: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------- | ------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **payload** | [**Payload**](/api-reference/rest/Payload) | | | ### Return type [**RecordingGenerationResponseSchema**](/api-reference/rest/RecordingGenerationResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment** > EnvironmentSchema src\_app\_api\_environments\_get\_environment(uuid) Get Environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment api_response = api_instance.src_app_api_environments_get_environment(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**EnvironmentSchema**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_dirty\_twins** > List\[Dict\[str, object]] src\_app\_api\_environments\_get\_environment\_dirty\_twins(uuid) Get Environment Dirty Twins List all twins in an environment whose snapshot schema is out of sync with their asset. Compares each twin's stored snapshot hash against the current asset schema hash. Returns list of dirty twin info with reasons. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Dirty Twins api_response = api_instance.src_app_api_environments_get_environment_dirty_twins(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_dirty_twins:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_dirty_twins: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **List\[Dict\[str, object]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_invitations** > Dict\[str, object] src\_app\_api\_environments\_get\_environment\_invitations(uuid) Get Environment Invitations Get pending invitations for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Invitations api_response = api_instance.src_app_api_environments_get_environment_invitations(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_invitations:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_invitations: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_mujoco\_scene** > src\_app\_api\_environments\_get\_environment\_mujoco\_scene(uuid) Get Environment Mujoco Scene Get MuJoCo scene ZIP file for an environment. Returns cached URL if available, otherwise triggers async generation. Cache format (new): * Success: `{"url": str, "created_at": str, "task_id": str, "status": "success"}` * Failure: `{"url": None, "created_at": str, "task_id": str, "status": "failed", "error": str}` * Legacy: Just the URL string (for backward compatibility) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Mujoco Scene api_instance.src_app_api_environments_get_environment_mujoco_scene(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_mujoco_scene: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_mujoco\_scene\_xml** > src\_app\_api\_environments\_get\_environment\_mujoco\_scene\_xml(uuid) Get Environment Mujoco Scene Xml Get self-contained MuJoCo scene xml for an environment. Composes schema from all twins' universal\_schemas and exports to MuJoCo XML. Note: Mesh file references will be absolute paths to converted files. For a complete scene with assets, use the /mujoco-scene endpoint to get a ZIP. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Mujoco Scene Xml api_instance.src_app_api_environments_get_environment_mujoco_scene_xml(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_mujoco_scene_xml: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_mujoco\_scene\_zip\_direct** > src\_app\_api\_environments\_get\_environment\_mujoco\_scene\_zip\_direct(uuid) Get Environment Mujoco Scene Zip Direct Get MuJoCo scene ZIP for an environment (direct download). Returns a ZIP file containing: * mujoco\_scene.xml at the root * assets/: Directory with all required mesh files Composes schema from all twins and exports to MuJoCo format. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Mujoco Scene Zip Direct api_instance.src_app_api_environments_get_environment_mujoco_scene_zip_direct(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_mujoco_scene_zip_direct: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_recordings** > Dict\[str, object] src\_app\_api\_environments\_get\_environment\_recordings(uuid) Get Environment Recordings Get all available recordings for an environment with pagination. Returns list of recording metadata excluding the recording\_path. Query params: * limit: Max number of records to return (default 50) * offset: Number of records to skip (default 0) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Recordings api_response = api_instance.src_app_api_environments_get_environment_recordings(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_recordings:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_recordings: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_sessions** > Dict\[str, object] src\_app\_api\_environments\_get\_environment\_sessions(uuid) Get Environment Sessions Get all recording sessions for an environment. Returns sessions for all twins in the environment, with start/end timestamps. This is the simplified session-based API that replaces the old twins-sessions endpoint. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Sessions api_response = api_instance.src_app_api_environments_get_environment_sessions(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_sessions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_sessions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_sharing\_info\_endpoint** > Dict\[str, object] src\_app\_api\_environments\_get\_environment\_sharing\_info\_endpoint(uuid) Get Environment Sharing Info Endpoint Get environment sharing and ACL information ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Sharing Info Endpoint api_response = api_instance.src_app_api_environments_get_environment_sharing_info_endpoint(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_sharing_info_endpoint:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_sharing_info_endpoint: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_simulations** > Dict\[str, object] src\_app\_api\_environments\_get\_environment\_simulations(uuid) Get Environment Simulations ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Simulations api_response = api_instance.src_app_api_environments_get_environment_simulations(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_simulations:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_simulations: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_snapshot** > EnvironmentSnapshotSchema src\_app\_api\_environments\_get\_environment\_snapshot(uuid, snapshot\_uuid) Get Environment Snapshot Get a snapshot for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_snapshot_schema import EnvironmentSnapshotSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | snapshot_uuid = 'snapshot_uuid_example' # str | try: # Get Environment Snapshot api_response = api_instance.src_app_api_environments_get_environment_snapshot(uuid, snapshot_uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_snapshot:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_snapshot: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **uuid** | **str** | | | | **snapshot\_uuid** | **str** | | | ### Return type [**EnvironmentSnapshotSchema**](/api-reference/rest/EnvironmentSnapshotSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_snapshot\_hash** > Dict\[str, Optional\[str]] src\_app\_api\_environments\_get\_environment\_snapshot\_hash(uuid) Get Environment Snapshot Hash Get the current snapshot hash key for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Snapshot Hash api_response = api_instance.src_app_api_environments_get_environment_snapshot_hash(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_snapshot_hash:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_snapshot_hash: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, Optional\[str]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_twins** > List\[TwinSchema] src\_app\_api\_environments\_get\_environment\_twins(uuid) Get Environment Twins Get twins in an environment with optional dynamic filters. Supports filtering on any field using query parameters with Django lookup syntax. Examples: * GET `/environments/{uuid}/twins?position_x**gte=0&position_x**lte=10` * GET `/environments/{uuid}/twins?capabilities\_\_locomotion_mode=wheeled` * GET `/environments/{uuid}/twins?metadata**power**battery_percent\_\_gte=20` * GET `/environments/{uuid}/twins?metadata**amr**navigation\_\_status=idle` * GET `/environments/{uuid}/twins?asset\_\_uuid=xxx` * GET `/environments/{uuid}/twins?capabilities**amr**vehicle_type=forklift` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_schema import TwinSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Twins api_response = api_instance.src_app_api_environments_get_environment_twins(uuid) print("The response of DefaultApi->src_app_api_environments_get_environment_twins:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_twins: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[TwinSchema\]**](/api-reference/rest/TwinSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_universal\_schema** > src\_app\_api\_environments\_get\_environment\_universal\_schema(uuid) Get Environment Universal Schema Get universal schema JSON file URL for an environment (cached). Returns cached URL if available, otherwise triggers async generation. Cache format: * Success: `{"url": str, "created_at": str, "task_id": str, "status": "success"}` * Failure: `{"url": None, "created_at": str, "task_id": str, "status": "failed", "error": str}` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Universal Schema api_instance.src_app_api_environments_get_environment_universal_schema(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_universal_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_universal\_schema\_json** > src\_app\_api\_environments\_get\_environment\_universal\_schema\_json(uuid) Get Environment Universal Schema Json Get the universal schema JSON for an environment (direct download). Composes schema from all twins' universal\_schemas. Returns an HTTP attachment with JSON content. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Universal Schema Json api_instance.src_app_api_environments_get_environment_universal_schema_json(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_universal_schema_json: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_urdf\_bundle** > src\_app\_api\_environments\_get\_environment\_urdf\_bundle(uuid) Get Environment Urdf Bundle Get environment URDF bundle URL for browser viewer (cached). Returns the URL to the extracted URDF bundle (scene.urdf + assets/) which can be loaded directly by the browser URDF viewer. The bundle is versioned by the environment's hash\_key, so changes to twin schemas will result in a new URL. Returns cached URL if available, otherwise triggers async generation. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Urdf Bundle api_instance.src_app_api_environments_get_environment_urdf_bundle(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_urdf_bundle: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_urdf\_scene** > src\_app\_api\_environments\_get\_environment\_urdf\_scene(uuid) Get Environment Urdf Scene Get URDF scene ZIP file URL for an environment (cached). Returns cached URL if available, otherwise triggers async generation. Cache format: * Success: `{"url": str, "created_at": str, "task_id": str, "status": "success"}` * Failure: `{"url": None, "created_at": str, "task_id": str, "status": "failed", "error": str}` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Urdf Scene api_instance.src_app_api_environments_get_environment_urdf_scene(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_urdf_scene: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_environment\_urdf\_scene\_zip\_direct** > src\_app\_api\_environments\_get\_environment\_urdf\_scene\_zip\_direct(uuid) Get Environment Urdf Scene Zip Direct Get URDF scene ZIP for an environment (direct download). Returns a ZIP file containing: * scene.urdf: The complete URDF scene * assets/: Directory with all required mesh files Composes schema from all twins and exports to URDF format. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Environment Urdf Scene Zip Direct api_instance.src_app_api_environments_get_environment_urdf_scene_zip_direct(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_environment_urdf_scene_zip_direct: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_my\_environment\_permissions** > PermissionsSchema src\_app\_api\_environments\_get\_my\_environment\_permissions(uuid) Get My Environment Permissions Get current user's permissions on this environment. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.permissions_schema import PermissionsSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get My Environment Permissions api_response = api_instance.src_app_api_environments_get_my_environment_permissions(uuid) print("The response of DefaultApi->src_app_api_environments_get_my_environment_permissions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_my_environment_permissions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**PermissionsSchema**](/api-reference/rest/PermissionsSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_get\_recording\_data** > Dict\[str, object] src\_app\_api\_environments\_get\_recording\_data(uuid, recording\_uuid, sample\_rate\_hz=sample\_rate\_hz) Get Recording Data Get sampled recording data for visualization. Returns timestamps and observation states sampled at the specified rate. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | recording_uuid = 'recording_uuid_example' # str | sample_rate_hz = 10 # int | (optional) (default to 10) try: # Get Recording Data api_response = api_instance.src_app_api_environments_get_recording_data(uuid, recording_uuid, sample_rate_hz=sample_rate_hz) print("The response of DefaultApi->src_app_api_environments_get_recording_data:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_get_recording_data: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | | | **recording\_uuid** | **str** | | | | **sample\_rate\_hz** | **int** | | \[optional] \[default to 10] | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_import\_environment\_mujoco\_scene** > ImportResultSchema src\_app\_api\_environments\_import\_environment\_mujoco\_scene(uuid, file, replace\_existing=replace\_existing) Import Environment Mujoco Scene Import twins into an environment from a MuJoCo scene file. Accepts either: * A .xml file (raw MJCF scene) * A .zip file containing mujoco\_scene.xml at the root The scene must have been exported by Cyberwave (must contain the extensions.cyberwave.twins registry in the XML comments/schema metadata). Multipart form field: file (.xml or .zip) Query param: replace\_existing (bool, default false) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.import_result_schema import ImportResultSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | replace_existing = False # bool | (optional) (default to False) try: # Import Environment Mujoco Scene api_response = api_instance.src_app_api_environments_import_environment_mujoco_scene(uuid, file, replace_existing=replace_existing) print("The response of DefaultApi->src_app_api_environments_import_environment_mujoco_scene:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_import_environment_mujoco_scene: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------- | ------------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **file** | **bytearray** | | | | **replace\_existing** | **bool** | | \[optional] \[default to False] | ### Return type [**ImportResultSchema**](/api-reference/rest/ImportResultSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_import\_environment\_universal\_schema** > ImportResultSchema src\_app\_api\_environments\_import\_environment\_universal\_schema(uuid, file, replace\_existing=replace\_existing) Import Environment Universal Schema Import twins into an environment from a Cyberwave universal schema JSON file. The JSON must contain an extensions.cyberwave.twins registry (i.e. it must have been exported by Cyberwave via GET `/{uuid}/universal-schema.json`). Multipart form field: file (.json) Query param: replace\_existing (bool, default false) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.import_result_schema import ImportResultSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | replace_existing = False # bool | (optional) (default to False) try: # Import Environment Universal Schema api_response = api_instance.src_app_api_environments_import_environment_universal_schema(uuid, file, replace_existing=replace_existing) print("The response of DefaultApi->src_app_api_environments_import_environment_universal_schema:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_import_environment_universal_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------- | ------------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **file** | **bytearray** | | | | **replace\_existing** | **bool** | | \[optional] \[default to False] | ### Return type [**ImportResultSchema**](/api-reference/rest/ImportResultSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_import\_environment\_urdf** > ImportResultSchema src\_app\_api\_environments\_import\_environment\_urdf(uuid, file, replace\_existing=replace\_existing, asset\_uuid=asset\_uuid, asset\_registry\_id=asset\_registry\_id, position\_x=position\_x, position\_y=position\_y, position\_z=position\_z, rotation\_x=rotation\_x, rotation\_y=rotation\_y, rotation\_z=rotation\_z, rotation\_w=rotation\_w) Import Environment Urdf Import a single robot twin into an environment from a URDF file. The URDF describes one robot; you must identify the matching Cyberwave Asset via asset\_uuid or asset\_registry\_id so the twin can be linked correctly. Multipart form field: file (.urdf) Query params: asset\_uuid / asset\_registry\_id - required: identifies the Cyberwave Asset position\_x/y/z - world position for the spawned twin (default 0,0,0) rotation\_x/y/z/w - world orientation quaternion (default identity) replace\_existing - if true, delete existing twins first ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.import_result_schema import ImportResultSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | replace_existing = False # bool | (optional) (default to False) asset_uuid = 'asset_uuid_example' # str | (optional) asset_registry_id = 'asset_registry_id_example' # str | (optional) position_x = 0.0 # float | (optional) (default to 0.0) position_y = 0.0 # float | (optional) (default to 0.0) position_z = 0.0 # float | (optional) (default to 0.0) rotation_x = 0.0 # float | (optional) (default to 0.0) rotation_y = 0.0 # float | (optional) (default to 0.0) rotation_z = 0.0 # float | (optional) (default to 0.0) rotation_w = 1.0 # float | (optional) (default to 1.0) try: # Import Environment Urdf api_response = api_instance.src_app_api_environments_import_environment_urdf(uuid, file, replace_existing=replace_existing, asset_uuid=asset_uuid, asset_registry_id=asset_registry_id, position_x=position_x, position_y=position_y, position_z=position_z, rotation_x=rotation_x, rotation_y=rotation_y, rotation_z=rotation_z, rotation_w=rotation_w) print("The response of DefaultApi->src_app_api_environments_import_environment_urdf:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_import_environment_urdf: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------- | ------------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **file** | **bytearray** | | | | **replace\_existing** | **bool** | | \[optional] \[default to False] | | **asset\_uuid** | **str** | | \[optional] | | **asset\_registry\_id** | **str** | | \[optional] | | **position\_x** | **float** | | \[optional] \[default to 0.0] | | **position\_y** | **float** | | \[optional] \[default to 0.0] | | **position\_z** | **float** | | \[optional] \[default to 0.0] | | **rotation\_x** | **float** | | \[optional] \[default to 0.0] | | **rotation\_y** | **float** | | \[optional] \[default to 0.0] | | **rotation\_z** | **float** | | \[optional] \[default to 0.0] | | **rotation\_w** | **float** | | \[optional] \[default to 1.0] | ### Return type [**ImportResultSchema**](/api-reference/rest/ImportResultSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_invite\_user\_to\_environment** > Dict\[str, object] src\_app\_api\_environments\_invite\_user\_to\_environment(uuid) Invite User To Environment Invite a non-existent user to an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Invite User To Environment api_response = api_instance.src_app_api_environments_invite_user_to_environment(uuid) print("The response of DefaultApi->src_app_api_environments_invite_user_to_environment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_invite_user_to_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_list\_all\_environments** > List\[EnvironmentSchema] src\_app\_api\_environments\_list\_all\_environments() List All Environments ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List All Environments api_response = api_instance.src_app_api_environments_list_all_environments() print("The response of DefaultApi->src_app_api_environments_list_all_environments:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_list_all_environments: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[EnvironmentSchema\]**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_list\_environment\_mission\_executions** > List\[MissionExecutionSchema] src\_app\_api\_environments\_list\_environment\_mission\_executions(uuid, status=status, twin\_uuid=twin\_uuid, limit=limit) List Environment Mission Executions List mission executions for all twins in an environment. Args: uuid: Environment UUID status: Filter by status (pending, running, paused, completed, failed, cancelled) twin\_uuid: Filter by specific twin UUID limit: Maximum number of results (default 100) Returns: List of mission executions ordered by created\_at (newest first) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.mission_execution_schema import MissionExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | status = 'status_example' # str | (optional) twin_uuid = 'twin_uuid_example' # str | (optional) limit = 100 # int | (optional) (default to 100) try: # List Environment Mission Executions api_response = api_instance.src_app_api_environments_list_environment_mission_executions(uuid, status=status, twin_uuid=twin_uuid, limit=limit) print("The response of DefaultApi->src_app_api_environments_list_environment_mission_executions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_list_environment_mission_executions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----------------------------- | | **uuid** | **str** | | | | **status** | **str** | | \[optional] | | **twin\_uuid** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**List\[MissionExecutionSchema\]**](/api-reference/rest/MissionExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_list\_environment\_snapshots** > List\[EnvironmentSnapshotSchema] src\_app\_api\_environments\_list\_environment\_snapshots(uuid) List Environment Snapshots List all snapshots for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_snapshot_schema import EnvironmentSnapshotSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Environment Snapshots api_response = api_instance.src_app_api_environments_list_environment_snapshots(uuid) print("The response of DefaultApi->src_app_api_environments_list_environment_snapshots:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_list_environment_snapshots: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[EnvironmentSnapshotSchema\]**](/api-reference/rest/EnvironmentSnapshotSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_list\_environment\_task\_executions** > List\[TaskExecutionSchema] src\_app\_api\_environments\_list\_environment\_task\_executions(uuid, status=status, twin\_uuid=twin\_uuid, limit=limit) List Environment Task Executions List task executions for all twins in an environment. Args: uuid: Environment UUID status: Filter by status (pending, running, completed, failed, cancelled) twin\_uuid: Filter by specific twin UUID limit: Maximum number of results (default 100) Returns: List of task executions ordered by created\_at (newest first) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.task_execution_schema import TaskExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | status = 'status_example' # str | (optional) twin_uuid = 'twin_uuid_example' # str | (optional) limit = 100 # int | (optional) (default to 100) try: # List Environment Task Executions api_response = api_instance.src_app_api_environments_list_environment_task_executions(uuid, status=status, twin_uuid=twin_uuid, limit=limit) print("The response of DefaultApi->src_app_api_environments_list_environment_task_executions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_list_environment_task_executions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----------------------------- | | **uuid** | **str** | | | | **status** | **str** | | \[optional] | | **twin\_uuid** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**List\[TaskExecutionSchema\]**](/api-reference/rest/TaskExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_list\_environments\_for\_project** > List\[EnvironmentSchema] src\_app\_api\_environments\_list\_environments\_for\_project(uuid) List Environments For Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Environments For Project api_response = api_instance.src_app_api_environments_list_environments_for_project(uuid) print("The response of DefaultApi->src_app_api_environments_list_environments_for_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_list_environments_for_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[EnvironmentSchema\]**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_process\_all\_environment\_sessions** > Dict\[str, object] src\_app\_api\_environments\_process\_all\_environment\_sessions(uuid) Process All Environment Sessions Process all recording sessions for all twins in the environment. This endpoint will: 1. Discover all twins in the environment 2. Find all sessions for each twin 3. Queue recording generation tasks for each session Returns information about queued tasks. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Process All Environment Sessions api_response = api_instance.src_app_api_environments_process_all_environment_sessions(uuid) print("The response of DefaultApi->src_app_api_environments_process_all_environment_sessions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_process_all_environment_sessions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_remove\_user\_from\_environment** > Dict\[str, object] src\_app\_api\_environments\_remove\_user\_from\_environment(uuid, user\_id) Remove User From Environment Remove user access from environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | user_id = 'user_id_example' # str | try: # Remove User From Environment api_response = api_instance.src_app_api_environments_remove_user_from_environment(uuid, user_id) print("The response of DefaultApi->src_app_api_environments_remove_user_from_environment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_remove_user_from_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **uuid** | **str** | | | | **user\_id** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_reset\_environment** > Dict\[str, object] src\_app\_api\_environments\_reset\_environment(uuid) Reset Environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Reset Environment api_response = api_instance.src_app_api_environments_reset_environment(uuid) print("The response of DefaultApi->src_app_api_environments_reset_environment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_reset_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_restore\_environment\_snapshot** > EnvironmentSchema src\_app\_api\_environments\_restore\_environment\_snapshot(uuid, snapshot\_uuid) Restore Environment Snapshot Restore a snapshot for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | snapshot_uuid = 'snapshot_uuid_example' # str | try: # Restore Environment Snapshot api_response = api_instance.src_app_api_environments_restore_environment_snapshot(uuid, snapshot_uuid) print("The response of DefaultApi->src_app_api_environments_restore_environment_snapshot:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_restore_environment_snapshot: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **uuid** | **str** | | | | **snapshot\_uuid** | **str** | | | ### Return type [**EnvironmentSchema**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_revoke\_environment\_link** > Dict\[str, object] src\_app\_api\_environments\_revoke\_environment\_link(uuid) Revoke Environment Link Revoke a shareable link for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Revoke Environment Link api_response = api_instance.src_app_api_environments_revoke_environment_link(uuid) print("The response of DefaultApi->src_app_api_environments_revoke_environment_link:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_revoke_environment_link: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_share\_environment\_with\_user** > Dict\[str, object] src\_app\_api\_environments\_share\_environment\_with\_user(uuid) Share Environment With User Share environment with a user by email ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Share Environment With User api_response = api_instance.src_app_api_environments_share_environment_with_user(uuid) print("The response of DefaultApi->src_app_api_environments_share_environment_with_user:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_share_environment_with_user: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_stop\_environment\_simulation** > Dict\[str, object] src\_app\_api\_environments\_stop\_environment\_simulation(uuid, simulation\_id) Stop Environment Simulation ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | simulation_id = 'simulation_id_example' # str | try: # Stop Environment Simulation api_response = api_instance.src_app_api_environments_stop_environment_simulation(uuid, simulation_id) print("The response of DefaultApi->src_app_api_environments_stop_environment_simulation:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_stop_environment_simulation: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **uuid** | **str** | | | | **simulation\_id** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_update\_environment** > EnvironmentSchema src\_app\_api\_environments\_update\_environment(uuid, environment\_create\_schema) Update Environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_create_schema import EnvironmentCreateSchema from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | environment_create_schema = cyberwave.rest.EnvironmentCreateSchema() # EnvironmentCreateSchema | try: # Update Environment api_response = api_instance.src_app_api_environments_update_environment(uuid, environment_create_schema) print("The response of DefaultApi->src_app_api_environments_update_environment:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_update_environment: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **environment\_create\_schema** | [**EnvironmentCreateSchema**](/api-reference/rest/EnvironmentCreateSchema) | | | ### Return type [**EnvironmentSchema**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_update\_environment\_for\_project** > EnvironmentSchema src\_app\_api\_environments\_update\_environment\_for\_project(project\_uuid, uuid, environment\_create\_schema) Update Environment For Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_create_schema import EnvironmentCreateSchema from cyberwave.rest.models.environment_schema import EnvironmentSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) project_uuid = 'project_uuid_example' # str | uuid = 'uuid_example' # str | environment_create_schema = cyberwave.rest.EnvironmentCreateSchema() # EnvironmentCreateSchema | try: # Update Environment For Project api_response = api_instance.src_app_api_environments_update_environment_for_project(project_uuid, uuid, environment_create_schema) print("The response of DefaultApi->src_app_api_environments_update_environment_for_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_update_environment_for_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **project\_uuid** | **str** | | | | **uuid** | **str** | | | | **environment\_create\_schema** | [**EnvironmentCreateSchema**](/api-reference/rest/EnvironmentCreateSchema) | | | ### Return type [**EnvironmentSchema**](/api-reference/rest/EnvironmentSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_update\_environment\_snapshot** > EnvironmentSnapshotSchema src\_app\_api\_environments\_update\_environment\_snapshot(uuid, snapshot\_uuid) Update Environment Snapshot Update a snapshot for an environment ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.environment_snapshot_schema import EnvironmentSnapshotSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | snapshot_uuid = 'snapshot_uuid_example' # str | try: # Update Environment Snapshot api_response = api_instance.src_app_api_environments_update_environment_snapshot(uuid, snapshot_uuid) print("The response of DefaultApi->src_app_api_environments_update_environment_snapshot:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_update_environment_snapshot: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------ | ------- | ----------- | ----- | | **uuid** | **str** | | | | **snapshot\_uuid** | **str** | | | ### Return type [**EnvironmentSnapshotSchema**](/api-reference/rest/EnvironmentSnapshotSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_environments\_update\_recording\_metadata** > TwinTelemetryMetadataSchema src\_app\_api\_environments\_update\_recording\_metadata(uuid, recording\_uuid, update\_recording\_metadata\_schema) Update Recording Metadata Update recording metadata (e.g., session name). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_telemetry_metadata_schema import TwinTelemetryMetadataSchema from cyberwave.rest.models.update_recording_metadata_schema import UpdateRecordingMetadataSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | recording_uuid = 'recording_uuid_example' # str | update_recording_metadata_schema = cyberwave.rest.UpdateRecordingMetadataSchema() # UpdateRecordingMetadataSchema | try: # Update Recording Metadata api_response = api_instance.src_app_api_environments_update_recording_metadata(uuid, recording_uuid, update_recording_metadata_schema) print("The response of DefaultApi->src_app_api_environments_update_recording_metadata:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_environments_update_recording_metadata: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **recording\_uuid** | **str** | | | | **update\_recording\_metadata\_schema** | [**UpdateRecordingMetadataSchema**](/api-reference/rest/UpdateRecordingMetadataSchema) | | | ### Return type [**TwinTelemetryMetadataSchema**](/api-reference/rest/TwinTelemetryMetadataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_episode\_create\_episode** > EpisodeSchema src\_app\_api\_episode\_create\_episode(episode\_create\_schema) Create Episode Create a new episode. Timestamps in microseconds. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.episode_create_schema import EpisodeCreateSchema from cyberwave.rest.models.episode_schema import EpisodeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) episode_create_schema = cyberwave.rest.EpisodeCreateSchema() # EpisodeCreateSchema | try: # Create Episode api_response = api_instance.src_app_api_episode_create_episode(episode_create_schema) print("The response of DefaultApi->src_app_api_episode_create_episode:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_episode_create_episode: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **episode\_create\_schema** | [**EpisodeCreateSchema**](/api-reference/rest/EpisodeCreateSchema) | | | ### Return type [**EpisodeSchema**](/api-reference/rest/EpisodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_episode\_delete\_episode** > Dict\[str, Optional\[bool]] src\_app\_api\_episode\_delete\_episode(uuid) Delete Episode Delete an episode. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Episode api_response = api_instance.src_app_api_episode_delete_episode(uuid) print("The response of DefaultApi->src_app_api_episode_delete_episode:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_episode_delete_episode: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, Optional\[bool]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_episode\_get\_episode** > EpisodeSchema src\_app\_api\_episode\_get\_episode(uuid) Get Episode Get a specific episode by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.episode_schema import EpisodeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Episode api_response = api_instance.src_app_api_episode_get_episode(uuid) print("The response of DefaultApi->src_app_api_episode_get_episode:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_episode_get_episode: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**EpisodeSchema**](/api-reference/rest/EpisodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_episode\_list\_episode\_task\_names** > List\[Optional\[str]] src\_app\_api\_episode\_list\_episode\_task\_names() List Episode Task Names List distinct task names for episodes in the given environment (for autocomplete suggestions). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Episode Task Names api_response = api_instance.src_app_api_episode_list_episode_task_names() print("The response of DefaultApi->src_app_api_episode_list_episode_task_names:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_episode_list_episode_task_names: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type **List\[Optional\[str]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_episode\_list\_episodes** > List\[EpisodeSchema] src\_app\_api\_episode\_list\_episodes() List Episodes List all episodes visible to the current user. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.episode_schema import EpisodeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Episodes api_response = api_instance.src_app_api_episode_list_episodes() print("The response of DefaultApi->src_app_api_episode_list_episodes:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_episode_list_episodes: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[EpisodeSchema\]**](/api-reference/rest/EpisodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_episode\_update\_episode** > EpisodeSchema src\_app\_api\_episode\_update\_episode(uuid, episode\_update\_schema) Update Episode Update an episode. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.episode_schema import EpisodeSchema from cyberwave.rest.models.episode_update_schema import EpisodeUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | episode_update_schema = cyberwave.rest.EpisodeUpdateSchema() # EpisodeUpdateSchema | try: # Update Episode api_response = api_instance.src_app_api_episode_update_episode(uuid, episode_update_schema) print("The response of DefaultApi->src_app_api_episode_update_episode:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_episode_update_episode: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **episode\_update\_schema** | [**EpisodeUpdateSchema**](/api-reference/rest/EpisodeUpdateSchema) | | | ### Return type [**EpisodeSchema**](/api-reference/rest/EpisodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_events\_create\_business\_event** > BusinessEventSchema src\_app\_api\_events\_create\_business\_event(business\_event\_create\_schema) Create Business Event Create a business event and trigger matching workflows. Sources: sensor, robot, edge\_node, workflow, user, system For ML model events, use source='edge\_node' or 'system' and include model details in the data field: `{"model": "yolo-v8", "version": "1.0", ...}` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.business_event_create_schema import BusinessEventCreateSchema from cyberwave.rest.models.business_event_schema import BusinessEventSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) business_event_create_schema = cyberwave.rest.BusinessEventCreateSchema() # BusinessEventCreateSchema | try: # Create Business Event api_response = api_instance.src_app_api_events_create_business_event(business_event_create_schema) print("The response of DefaultApi->src_app_api_events_create_business_event:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_events_create_business_event: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | ------------------------------------------------------------------------------ | ----------- | ----- | | **business\_event\_create\_schema** | [**BusinessEventCreateSchema**](/api-reference/rest/BusinessEventCreateSchema) | | | ### Return type [**BusinessEventSchema**](/api-reference/rest/BusinessEventSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_events\_list\_live\_events** > BusinessEventListResponseSchema src\_app\_api\_events\_list\_live\_events(environment\_uuid=environment\_uuid, source=source, severity=severity, event\_type=event\_type, last\_timestamp\_ms=last\_timestamp\_ms, limit=limit) List Live Events Get recent business events for live visualization. Supports filtering by: * environment\_uuid: Filter by environment * source: Filter by source type (sensor, robot, edge\_node, workflow, user, system) * severity: Filter by severity level (DEBUG, INFO, WARNING, ERROR, CRITICAL) * event\_type: Filter by event type (exact match) * last\_timestamp\_ms: Get events after this timestamp (for polling) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.business_event_list_response_schema import BusinessEventListResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) environment_uuid = 'environment_uuid_example' # str | (optional) source = 'source_example' # str | (optional) severity = 'severity_example' # str | (optional) event_type = 'event_type_example' # str | (optional) last_timestamp_ms = 56 # int | (optional) limit = 100 # int | (optional) (default to 100) try: # List Live Events api_response = api_instance.src_app_api_events_list_live_events(environment_uuid=environment_uuid, source=source, severity=severity, event_type=event_type, last_timestamp_ms=last_timestamp_ms, limit=limit) print("The response of DefaultApi->src_app_api_events_list_live_events:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_events_list_live_events: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------- | ------- | ----------- | ----------------------------- | | **environment\_uuid** | **str** | | \[optional] | | **source** | **str** | | \[optional] | | **severity** | **str** | | \[optional] | | **event\_type** | **str** | | \[optional] | | **last\_timestamp\_ms** | **int** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**BusinessEventListResponseSchema**](/api-reference/rest/BusinessEventListResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_executions\_get\_task\_execution** > DeferredTaskExecutionResponseSchema src\_app\_api\_executions\_get\_task\_execution(uuid, workspace\_uuid) Get Task Execution Get a specific execution by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.deferred_task_execution_response_schema import DeferredTaskExecutionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workspace_uuid = 'workspace_uuid_example' # str | try: # Get Task Execution api_response = api_instance.src_app_api_executions_get_task_execution(uuid, workspace_uuid) print("The response of DefaultApi->src_app_api_executions_get_task_execution:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_executions_get_task_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **workspace\_uuid** | **str** | | | ### Return type [**DeferredTaskExecutionResponseSchema**](/api-reference/rest/DeferredTaskExecutionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_executions\_list\_task\_executions** > List\[DeferredTaskExecutionResponseSchema] src\_app\_api\_executions\_list\_task\_executions(workspace\_uuid) List Task Executions List all executions for a workspace. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.deferred_task_execution_response_schema import DeferredTaskExecutionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) workspace_uuid = 'workspace_uuid_example' # str | try: # List Task Executions api_response = api_instance.src_app_api_executions_list_task_executions(workspace_uuid) print("The response of DefaultApi->src_app_api_executions_list_task_executions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_executions_list_task_executions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **workspace\_uuid** | **str** | | | ### Return type [**List\[DeferredTaskExecutionResponseSchema\]**](/api-reference/rest/DeferredTaskExecutionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_invitation\_router\_accept\_invitation\_endpoint** > Dict\[str, object] src\_app\_api\_invitation\_router\_accept\_invitation\_endpoint(token) Accept Invitation Endpoint Accept a user invitation via token ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) token = 'token_example' # str | try: # Accept Invitation Endpoint api_response = api_instance.src_app_api_invitation_router_accept_invitation_endpoint(token) print("The response of DefaultApi->src_app_api_invitation_router_accept_invitation_endpoint:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_invitation_router_accept_invitation_endpoint: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------- | ------- | ----------- | ----- | | **token** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_invitation\_router\_get\_invitation\_info** > Dict\[str, object] src\_app\_api\_invitation\_router\_get\_invitation\_info(token) Get Invitation Info Get invitation info without accepting it ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) token = 'token_example' # str | try: # Get Invitation Info api_response = api_instance.src_app_api_invitation_router_get_invitation_info(token) print("The response of DefaultApi->src_app_api_invitation_router_get_invitation_info:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_invitation_router_get_invitation_info: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------- | ------- | ----------- | ----- | | **token** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_keybindings\_create\_keybinding** > KeybindingSchema src\_app\_api\_keybindings\_create\_keybinding(keybinding\_create\_schema) Create Keybinding Create a new keybinding. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.keybinding_create_schema import KeybindingCreateSchema from cyberwave.rest.models.keybinding_schema import KeybindingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) keybinding_create_schema = cyberwave.rest.KeybindingCreateSchema() # KeybindingCreateSchema | try: # Create Keybinding api_response = api_instance.src_app_api_keybindings_create_keybinding(keybinding_create_schema) print("The response of DefaultApi->src_app_api_keybindings_create_keybinding:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_keybindings_create_keybinding: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------ | ------------------------------------------------------------------------ | ----------- | ----- | | **keybinding\_create\_schema** | [**KeybindingCreateSchema**](/api-reference/rest/KeybindingCreateSchema) | | | ### Return type [**KeybindingSchema**](/api-reference/rest/KeybindingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_keybindings\_delete\_keybinding** > src\_app\_api\_keybindings\_delete\_keybinding(uuid) Delete Keybinding Delete a keybinding. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Keybinding api_instance.src_app_api_keybindings_delete_keybinding(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_keybindings_delete_keybinding: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_keybindings\_get\_keybinding** > KeybindingSchema src\_app\_api\_keybindings\_get\_keybinding(uuid) Get Keybinding Get a specific keybinding by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.keybinding_schema import KeybindingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Keybinding api_response = api_instance.src_app_api_keybindings_get_keybinding(uuid) print("The response of DefaultApi->src_app_api_keybindings_get_keybinding:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_keybindings_get_keybinding: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**KeybindingSchema**](/api-reference/rest/KeybindingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_keybindings\_list\_keybindings** > List\[KeybindingSchema] src\_app\_api\_keybindings\_list\_keybindings() List Keybindings List all keybindings for the authenticated user. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.keybinding_schema import KeybindingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Keybindings api_response = api_instance.src_app_api_keybindings_list_keybindings() print("The response of DefaultApi->src_app_api_keybindings_list_keybindings:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_keybindings_list_keybindings: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[KeybindingSchema\]**](/api-reference/rest/KeybindingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_keybindings\_update\_keybinding** > KeybindingSchema src\_app\_api\_keybindings\_update\_keybinding(uuid, keybinding\_update\_schema) Update Keybinding Update an existing keybinding. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.keybinding_schema import KeybindingSchema from cyberwave.rest.models.keybinding_update_schema import KeybindingUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | keybinding_update_schema = cyberwave.rest.KeybindingUpdateSchema() # KeybindingUpdateSchema | try: # Update Keybinding api_response = api_instance.src_app_api_keybindings_update_keybinding(uuid, keybinding_update_schema) print("The response of DefaultApi->src_app_api_keybindings_update_keybinding:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_keybindings_update_keybinding: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------ | ------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **keybinding\_update\_schema** | [**KeybindingUpdateSchema**](/api-reference/rest/KeybindingUpdateSchema) | | | ### Return type [**KeybindingSchema**](/api-reference/rest/KeybindingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_labs\_end\_milan\_lab\_session** > EndSessionResponseSchema src\_app\_api\_labs\_end\_milan\_lab\_session() End Milan Lab Session End the user's active session or cancel their queue entry. If the user had an active session the next queued user is automatically promoted to active. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.end_session_response_schema import EndSessionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # End Milan Lab Session api_response = api_instance.src_app_api_labs_end_milan_lab_session() print("The response of DefaultApi->src_app_api_labs_end_milan_lab_session:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_labs_end_milan_lab_session: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**EndSessionResponseSchema**](/api-reference/rest/EndSessionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_labs\_get\_milan\_lab\_status** > LabStatusResponseSchema src\_app\_api\_labs\_get\_milan\_lab\_status() Get Milan Lab Status Get current status of the Milan SO101 lab for the requesting user. Returns whether the lab is free or in use, the user's session state (active / queued / none), queue position, and estimated wait time. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.lab_status_response_schema import LabStatusResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Milan Lab Status api_response = api_instance.src_app_api_labs_get_milan_lab_status() print("The response of DefaultApi->src_app_api_labs_get_milan_lab_status:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_labs_get_milan_lab_status: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**LabStatusResponseSchema**](/api-reference/rest/LabStatusResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_labs\_request\_milan\_lab\_access** > LabAccessResponseSchema src\_app\_api\_labs\_request\_milan\_lab\_access(body) Request Milan Lab Access Request access to the Milan SO101 lab. * If the lab is free the user gets immediate access (10-min session). * If the lab is in use the user is added to the queue. * Idempotent: calling again while active/queued returns the existing session. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.lab_access_response_schema import LabAccessResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) body = None # object | try: # Request Milan Lab Access api_response = api_instance.src_app_api_labs_request_milan_lab_access(body) print("The response of DefaultApi->src_app_api_labs_request_milan_lab_access:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_labs_request_milan_lab_access: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ---------- | ----------- | ----- | | **body** | **object** | | | ### Return type [**LabAccessResponseSchema**](/api-reference/rest/LabAccessResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_create\_map** > MapDataSchema src\_app\_api\_maps\_create\_map(map\_type, twin\_uuid=twin\_uuid, environment\_uuid=environment\_uuid, resolution=resolution, origin\_x=origin\_x, origin\_y=origin\_y, origin\_z=origin\_z, origin\_roll=origin\_roll, origin\_pitch=origin\_pitch, origin\_yaw=origin\_yaw, metadata=metadata, file=file) Create Map Create/upload a new map. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.models.metadata import Metadata from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) map_type = 'map_type_example' # str | twin_uuid = 'twin_uuid_example' # str | (optional) environment_uuid = 'environment_uuid_example' # str | (optional) resolution = 3.4 # float | (optional) origin_x = 0.0 # float | (optional) (default to 0.0) origin_y = 0.0 # float | (optional) (default to 0.0) origin_z = 0.0 # float | (optional) (default to 0.0) origin_roll = 0.0 # float | (optional) (default to 0.0) origin_pitch = 0.0 # float | (optional) (default to 0.0) origin_yaw = 0.0 # float | (optional) (default to 0.0) metadata = cyberwave.rest.Metadata() # Metadata | (optional) file = None # bytearray | (optional) try: # Create Map api_response = api_instance.src_app_api_maps_create_map(map_type, twin_uuid=twin_uuid, environment_uuid=environment_uuid, resolution=resolution, origin_x=origin_x, origin_y=origin_y, origin_z=origin_z, origin_roll=origin_roll, origin_pitch=origin_pitch, origin_yaw=origin_yaw, metadata=metadata, file=file) print("The response of DefaultApi->src_app_api_maps_create_map:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_create_map: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------- | -------------------------------------------- | ----------- | ----------------------------- | | **map\_type** | **str** | | | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **resolution** | **float** | | \[optional] | | **origin\_x** | **float** | | \[optional] \[default to 0.0] | | **origin\_y** | **float** | | \[optional] \[default to 0.0] | | **origin\_z** | **float** | | \[optional] \[default to 0.0] | | **origin\_roll** | **float** | | \[optional] \[default to 0.0] | | **origin\_pitch** | **float** | | \[optional] \[default to 0.0] | | **origin\_yaw** | **float** | | \[optional] \[default to 0.0] | | **metadata** | [**Metadata**](/api-reference/rest/Metadata) | | \[optional] | | **file** | **bytearray** | | \[optional] | ### Return type [**MapDataSchema**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_delete\_map** > src\_app\_api\_maps\_delete\_map(uuid) Delete Map Delete a map. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Map api_instance.src_app_api_maps_delete_map(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_delete_map: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_download\_map\_data** > src\_app\_api\_maps\_download\_map\_data(uuid) Download Map Data Download map data file. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Download Map Data api_instance.src_app_api_maps_download_map_data(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_download_map_data: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_finalize\_stream\_map** > MapDataSchema src\_app\_api\_maps\_finalize\_stream\_map(uuid, resolution=resolution, origin\_x=origin\_x, origin\_y=origin\_y, origin\_z=origin\_z, origin\_roll=origin\_roll, origin\_pitch=origin\_pitch, origin\_yaw=origin\_yaw, metadata=metadata, file=file) Finalize Stream Map Finalize a stream-started map by uploading the real map file. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.models.metadata import Metadata from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | resolution = 3.4 # float | (optional) origin_x = 3.4 # float | (optional) origin_y = 3.4 # float | (optional) origin_z = 3.4 # float | (optional) origin_roll = 3.4 # float | (optional) origin_pitch = 3.4 # float | (optional) origin_yaw = 3.4 # float | (optional) metadata = cyberwave.rest.Metadata() # Metadata | (optional) file = None # bytearray | (optional) try: # Finalize Stream Map api_response = api_instance.src_app_api_maps_finalize_stream_map(uuid, resolution=resolution, origin_x=origin_x, origin_y=origin_y, origin_z=origin_z, origin_roll=origin_roll, origin_pitch=origin_pitch, origin_yaw=origin_yaw, metadata=metadata, file=file) print("The response of DefaultApi->src_app_api_maps_finalize_stream_map:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_finalize_stream_map: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | -------------------------------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **resolution** | **float** | | \[optional] | | **origin\_x** | **float** | | \[optional] | | **origin\_y** | **float** | | \[optional] | | **origin\_z** | **float** | | \[optional] | | **origin\_roll** | **float** | | \[optional] | | **origin\_pitch** | **float** | | \[optional] | | **origin\_yaw** | **float** | | \[optional] | | **metadata** | [**Metadata**](/api-reference/rest/Metadata) | | \[optional] | | **file** | **bytearray** | | \[optional] | ### Return type [**MapDataSchema**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_get\_map** > MapDataSchema src\_app\_api\_maps\_get\_map(uuid) Get Map Get map metadata by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Map api_response = api_instance.src_app_api_maps_get_map(uuid) print("The response of DefaultApi->src_app_api_maps_get_map:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_get_map: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**MapDataSchema**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_get\_map\_image** > src\_app\_api\_maps\_get\_map\_image(uuid) Get Map Image Return the map data file converted to PNG (supports PGM, PBM, PPM, etc.). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Map Image api_instance.src_app_api_maps_get_map_image(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_get_map_image: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_list\_environment\_maps** > List\[MapDataSchema] src\_app\_api\_maps\_list\_environment\_maps(uuid) List Environment Maps List all maps in an environment (including maps from twins in that environment). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Environment Maps api_response = api_instance.src_app_api_maps_list_environment_maps(uuid) print("The response of DefaultApi->src_app_api_maps_list_environment_maps:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_list_environment_maps: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[MapDataSchema\]**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_list\_maps** > List\[MapDataSchema] src\_app\_api\_maps\_list\_maps() List Maps List all maps accessible to the user. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Maps api_response = api_instance.src_app_api_maps_list_maps() print("The response of DefaultApi->src_app_api_maps_list_maps:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_list_maps: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[MapDataSchema\]**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_list\_twin\_maps** > List\[MapDataSchema] src\_app\_api\_maps\_list\_twin\_maps(uuid) List Twin Maps List maps for a specific twin. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Twin Maps api_response = api_instance.src_app_api_maps_list_twin_maps(uuid) print("The response of DefaultApi->src_app_api_maps_list_twin_maps:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_list_twin_maps: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[MapDataSchema\]**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_start\_map\_from\_stream** > MapDataSchema src\_app\_api\_maps\_start\_map\_from\_stream(map\_stream\_start\_schema) Start Map From Stream Create a map entry to receive updates from a live stream. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.models.map_stream_start_schema import MapStreamStartSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) map_stream_start_schema = cyberwave.rest.MapStreamStartSchema() # MapStreamStartSchema | try: # Start Map From Stream api_response = api_instance.src_app_api_maps_start_map_from_stream(map_stream_start_schema) print("The response of DefaultApi->src_app_api_maps_start_map_from_stream:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_start_map_from_stream: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------ | -------------------------------------------------------------------- | ----------- | ----- | | **map\_stream\_start\_schema** | [**MapStreamStartSchema**](/api-reference/rest/MapStreamStartSchema) | | | ### Return type [**MapDataSchema**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_maps\_stop\_map\_from\_stream** > MapDataSchema src\_app\_api\_maps\_stop\_map\_from\_stream(map\_stream\_stop\_schema) Stop Map From Stream Queue a stop/finalize request for the active streaming map. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.map_data_schema import MapDataSchema from cyberwave.rest.models.map_stream_stop_schema import MapStreamStopSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) map_stream_stop_schema = cyberwave.rest.MapStreamStopSchema() # MapStreamStopSchema | try: # Stop Map From Stream api_response = api_instance.src_app_api_maps_stop_map_from_stream(map_stream_stop_schema) print("The response of DefaultApi->src_app_api_maps_stop_map_from_stream:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_maps_stop_map_from_stream: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **map\_stream\_stop\_schema** | [**MapStreamStopSchema**](/api-reference/rest/MapStreamStopSchema) | | | ### Return type [**MapDataSchema**](/api-reference/rest/MapDataSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_cancel\_mission\_execution** > src\_app\_api\_missions\_cancel\_mission\_execution(twin\_uuid, mission\_uuid, uuid) Cancel Mission Execution Cancel a mission execution. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | mission_uuid = 'mission_uuid_example' # str | uuid = 'uuid_example' # str | try: # Cancel Mission Execution api_instance.src_app_api_missions_cancel_mission_execution(twin_uuid, mission_uuid, uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_cancel_mission_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **mission\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_create\_mission** > MissionSchema src\_app\_api\_missions\_create\_mission(uuid, create\_mission\_schema) Create Mission Create a mission definition (sequential task list). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.create_mission_schema import CreateMissionSchema from cyberwave.rest.models.mission_schema import MissionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | create_mission_schema = cyberwave.rest.CreateMissionSchema() # CreateMissionSchema | try: # Create Mission api_response = api_instance.src_app_api_missions_create_mission(uuid, create_mission_schema) print("The response of DefaultApi->src_app_api_missions_create_mission:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_create_mission: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **create\_mission\_schema** | [**CreateMissionSchema**](/api-reference/rest/CreateMissionSchema) | | | ### Return type [**MissionSchema**](/api-reference/rest/MissionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_delete\_mission** > src\_app\_api\_missions\_delete\_mission(twin\_uuid, uuid) Delete Mission Delete a mission definition. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | uuid = 'uuid_example' # str | try: # Delete Mission api_instance.src_app_api_missions_delete_mission(twin_uuid, uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_delete_mission: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_execute\_mission** > MissionExecutionSchema src\_app\_api\_missions\_execute\_mission(twin\_uuid, uuid, create\_mission\_execution\_schema) Execute Mission Execute a mission (create a mission execution). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.create_mission_execution_schema import CreateMissionExecutionSchema from cyberwave.rest.models.mission_execution_schema import MissionExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | uuid = 'uuid_example' # str | create_mission_execution_schema = cyberwave.rest.CreateMissionExecutionSchema() # CreateMissionExecutionSchema | try: # Execute Mission api_response = api_instance.src_app_api_missions_execute_mission(twin_uuid, uuid, create_mission_execution_schema) print("The response of DefaultApi->src_app_api_missions_execute_mission:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_execute_mission: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------------- | ------------------------------------------------------------------------------------ | ----------- | ----- | | **twin\_uuid** | **str** | | | | **uuid** | **str** | | | | **create\_mission\_execution\_schema** | [**CreateMissionExecutionSchema**](/api-reference/rest/CreateMissionExecutionSchema) | | | ### Return type [**MissionExecutionSchema**](/api-reference/rest/MissionExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_get\_mission** > MissionSchema src\_app\_api\_missions\_get\_mission(twin\_uuid, uuid) Get Mission Get a mission definition by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.mission_schema import MissionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | uuid = 'uuid_example' # str | try: # Get Mission api_response = api_instance.src_app_api_missions_get_mission(twin_uuid, uuid) print("The response of DefaultApi->src_app_api_missions_get_mission:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_get_mission: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type [**MissionSchema**](/api-reference/rest/MissionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_get\_mission\_execution** > MissionExecutionSchema src\_app\_api\_missions\_get\_mission\_execution(twin\_uuid, mission\_uuid, uuid) Get Mission Execution Get a mission execution by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.mission_execution_schema import MissionExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | mission_uuid = 'mission_uuid_example' # str | uuid = 'uuid_example' # str | try: # Get Mission Execution api_response = api_instance.src_app_api_missions_get_mission_execution(twin_uuid, mission_uuid, uuid) print("The response of DefaultApi->src_app_api_missions_get_mission_execution:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_get_mission_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **mission\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type [**MissionExecutionSchema**](/api-reference/rest/MissionExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_list\_mission\_executions** > List\[MissionExecutionSchema] src\_app\_api\_missions\_list\_mission\_executions(twin\_uuid, uuid, status=status, limit=limit) List Mission Executions List executions for a mission definition. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.mission_execution_schema import MissionExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | uuid = 'uuid_example' # str | status = 'status_example' # str | (optional) limit = 50 # int | (optional) (default to 50) try: # List Mission Executions api_response = api_instance.src_app_api_missions_list_mission_executions(twin_uuid, uuid, status=status, limit=limit) print("The response of DefaultApi->src_app_api_missions_list_mission_executions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_list_mission_executions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ---------------------------- | | **twin\_uuid** | **str** | | | | **uuid** | **str** | | | | **status** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 50] | ### Return type [**List\[MissionExecutionSchema\]**](/api-reference/rest/MissionExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_missions\_list\_missions** > List\[MissionSchema] src\_app\_api\_missions\_list\_missions(uuid) List Missions List mission definitions for a twin. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.mission_schema import MissionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Missions api_response = api_instance.src_app_api_missions_list_missions(uuid) print("The response of DefaultApi->src_app_api_missions_list_missions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_missions_list_missions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[MissionSchema\]**](/api-reference/rest/MissionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mlmodels\_create\_mlmodel** > MLModelSchema src\_app\_api\_mlmodels\_create\_mlmodel(ml\_model\_create\_schema) Create Mlmodel Create a new ML model. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_model_create_schema import MLModelCreateSchema from cyberwave.rest.models.ml_model_schema import MLModelSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) ml_model_create_schema = cyberwave.rest.MLModelCreateSchema() # MLModelCreateSchema | try: # Create Mlmodel api_response = api_instance.src_app_api_mlmodels_create_mlmodel(ml_model_create_schema) print("The response of DefaultApi->src_app_api_mlmodels_create_mlmodel:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mlmodels_create_mlmodel: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **ml\_model\_create\_schema** | [**MLModelCreateSchema**](/api-reference/rest/MLModelCreateSchema) | | | ### Return type [**MLModelSchema**](/api-reference/rest/MLModelSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mlmodels\_delete\_mlmodel** > src\_app\_api\_mlmodels\_delete\_mlmodel(uuid) Delete Mlmodel Delete an ML model. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Mlmodel api_instance.src_app_api_mlmodels_delete_mlmodel(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mlmodels_delete_mlmodel: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mlmodels\_get\_mlmodel** > MLModelSchema src\_app\_api\_mlmodels\_get\_mlmodel(uuid) Get Mlmodel Get a specific ML model by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_model_schema import MLModelSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Mlmodel api_response = api_instance.src_app_api_mlmodels_get_mlmodel(uuid) print("The response of DefaultApi->src_app_api_mlmodels_get_mlmodel:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mlmodels_get_mlmodel: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**MLModelSchema**](/api-reference/rest/MLModelSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mlmodels\_get\_mlmodel\_weights** > Dict\[str, Optional\[str]] src\_app\_api\_mlmodels\_get\_mlmodel\_weights(uuid) Get Mlmodel Weights Get a signed URL for downloading the ML model checkpoint weights. The checkpoint is expected to be a tar archive containing the model files (config.json, adapter files, etc.) from training. Returns: Dict with signed\_url and expires\_at fields ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Mlmodel Weights api_response = api_instance.src_app_api_mlmodels_get_mlmodel_weights(uuid) print("The response of DefaultApi->src_app_api_mlmodels_get_mlmodel_weights:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mlmodels_get_mlmodel_weights: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, Optional\[str]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mlmodels\_list\_mlmodels** > List\[MLModelSchema] src\_app\_api\_mlmodels\_list\_mlmodels(deployment=deployment, edge\_compatible=edge\_compatible) List Mlmodels List all ML models for the authenticated user's workspace. Query params: deployment: Filter by deployment type (cloud, edge, hybrid) edge\_compatible: If true, return only edge or hybrid models ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_model_schema import MLModelSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) deployment = 'deployment_example' # str | (optional) edge_compatible = True # bool | (optional) try: # List Mlmodels api_response = api_instance.src_app_api_mlmodels_list_mlmodels(deployment=deployment, edge_compatible=edge_compatible) print("The response of DefaultApi->src_app_api_mlmodels_list_mlmodels:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mlmodels_list_mlmodels: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------- | -------- | ----------- | ----------- | | **deployment** | **str** | | \[optional] | | **edge\_compatible** | **bool** | | \[optional] | ### Return type [**List\[MLModelSchema\]**](/api-reference/rest/MLModelSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mlmodels\_update\_mlmodel** > MLModelSchema src\_app\_api\_mlmodels\_update\_mlmodel(uuid, ml\_model\_update\_schema) Update Mlmodel Update an existing ML model. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_model_schema import MLModelSchema from cyberwave.rest.models.ml_model_update_schema import MLModelUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | ml_model_update_schema = cyberwave.rest.MLModelUpdateSchema() # MLModelUpdateSchema | try: # Update Mlmodel api_response = api_instance.src_app_api_mlmodels_update_mlmodel(uuid, ml_model_update_schema) print("The response of DefaultApi->src_app_api_mlmodels_update_mlmodel:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mlmodels_update_mlmodel: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **ml\_model\_update\_schema** | [**MLModelUpdateSchema**](/api-reference/rest/MLModelUpdateSchema) | | | ### Return type [**MLModelSchema**](/api-reference/rest/MLModelSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_create\_mltraining** > Response src\_app\_api\_mltrainings\_create\_mltraining(ml\_training\_create\_schema) Create Mltraining Create a new ML training. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_training_create_schema import MLTrainingCreateSchema from cyberwave.rest.models.response import Response from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) ml_training_create_schema = cyberwave.rest.MLTrainingCreateSchema() # MLTrainingCreateSchema | try: # Create Mltraining api_response = api_instance.src_app_api_mltrainings_create_mltraining(ml_training_create_schema) print("The response of DefaultApi->src_app_api_mltrainings_create_mltraining:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_create_mltraining: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ------------------------------------------------------------------------ | ----------- | ----- | | **ml\_training\_create\_schema** | [**MLTrainingCreateSchema**](/api-reference/rest/MLTrainingCreateSchema) | | | ### Return type [**Response**](/api-reference/rest/Response) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_delete\_mltraining** > Dict\[str, object] src\_app\_api\_mltrainings\_delete\_mltraining(uuid) Delete Mltraining Delete an ML training. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Mltraining api_response = api_instance.src_app_api_mltrainings_delete_mltraining(uuid) print("The response of DefaultApi->src_app_api_mltrainings_delete_mltraining:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_delete_mltraining: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_deploy\_mltraining** > Dict\[str, object] src\_app\_api\_mltrainings\_deploy\_mltraining(uuid, ml\_training\_deploy\_schema) Deploy Mltraining Deploy a completed ML training to one or more twins. The deployment process: 1. Export the trained model weights 2. Create a new ControllerPolicy (type: mlmodel) with the trained model 3. Assign the controller policy to the specified twins TODO: Implement actual deployment logic: * Export trained model weights to storage * Create ControllerPolicy with type='mlmodel' and model reference * Update each twin's controller\_policy FK to the new policy * Optionally start inference service ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_training_deploy_schema import MLTrainingDeploySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | ml_training_deploy_schema = cyberwave.rest.MLTrainingDeploySchema() # MLTrainingDeploySchema | try: # Deploy Mltraining api_response = api_instance.src_app_api_mltrainings_deploy_mltraining(uuid, ml_training_deploy_schema) print("The response of DefaultApi->src_app_api_mltrainings_deploy_mltraining:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_deploy_mltraining: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **ml\_training\_deploy\_schema** | [**MLTrainingDeploySchema**](/api-reference/rest/MLTrainingDeploySchema) | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_get\_deployed\_mltrainings** > List\[MLTrainingSchema] src\_app\_api\_mltrainings\_get\_deployed\_mltrainings() Get Deployed Mltrainings Get all deployed ML trainings for the authenticated user's workspaces. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_training_schema import MLTrainingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Deployed Mltrainings api_response = api_instance.src_app_api_mltrainings_get_deployed_mltrainings() print("The response of DefaultApi->src_app_api_mltrainings_get_deployed_mltrainings:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_get_deployed_mltrainings: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[MLTrainingSchema\]**](/api-reference/rest/MLTrainingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_get\_mltraining** > MLTrainingSchema src\_app\_api\_mltrainings\_get\_mltraining(uuid) Get Mltraining Get a specific ML training by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_training_schema import MLTrainingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Mltraining api_response = api_instance.src_app_api_mltrainings_get_mltraining(uuid) print("The response of DefaultApi->src_app_api_mltrainings_get_mltraining:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_get_mltraining: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**MLTrainingSchema**](/api-reference/rest/MLTrainingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_list\_mltrainings\_for\_user\_workspaces** > List\[MLTrainingSchema] src\_app\_api\_mltrainings\_list\_mltrainings\_for\_user\_workspaces() List Mltrainings For User Workspaces List all ML trainings for the authenticated user's workspaces. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_training_schema import MLTrainingSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Mltrainings For User Workspaces api_response = api_instance.src_app_api_mltrainings_list_mltrainings_for_user_workspaces() print("The response of DefaultApi->src_app_api_mltrainings_list_mltrainings_for_user_workspaces:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_list_mltrainings_for_user_workspaces: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[MLTrainingSchema\]**](/api-reference/rest/MLTrainingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_mltrainings\_update\_mltraining** > MLTrainingSchema src\_app\_api\_mltrainings\_update\_mltraining(uuid, ml\_training\_update\_schema) Update Mltraining Update an ML training. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.ml_training_schema import MLTrainingSchema from cyberwave.rest.models.ml_training_update_schema import MLTrainingUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | ml_training_update_schema = cyberwave.rest.MLTrainingUpdateSchema() # MLTrainingUpdateSchema | try: # Update Mltraining api_response = api_instance.src_app_api_mltrainings_update_mltraining(uuid, ml_training_update_schema) print("The response of DefaultApi->src_app_api_mltrainings_update_mltraining:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_mltrainings_update_mltraining: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **ml\_training\_update\_schema** | [**MLTrainingUpdateSchema**](/api-reference/rest/MLTrainingUpdateSchema) | | | ### Return type [**MLTrainingSchema**](/api-reference/rest/MLTrainingSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_navigation\_execute\_twin\_navigation** > TwinActionResponseSchema src\_app\_api\_navigation\_execute\_twin\_navigation(uuid, twin\_navigation\_command\_schema) Execute Twin Navigation ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_action_response_schema import TwinActionResponseSchema from cyberwave.rest.models.twin_navigation_command_schema import TwinNavigationCommandSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_navigation_command_schema = cyberwave.rest.TwinNavigationCommandSchema() # TwinNavigationCommandSchema | try: # Execute Twin Navigation api_response = api_instance.src_app_api_navigation_execute_twin_navigation(uuid, twin_navigation_command_schema) print("The response of DefaultApi->src_app_api_navigation_execute_twin_navigation:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_navigation_execute_twin_navigation: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------- | ---------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_navigation\_command\_schema** | [**TwinNavigationCommandSchema**](/api-reference/rest/TwinNavigationCommandSchema) | | | ### Return type [**TwinActionResponseSchema**](/api-reference/rest/TwinActionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_create\_project** > ProjectSchema src\_app\_api\_projects\_create\_project(project\_create\_schema) Create Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.project_create_schema import ProjectCreateSchema from cyberwave.rest.models.project_schema import ProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) project_create_schema = cyberwave.rest.ProjectCreateSchema() # ProjectCreateSchema | try: # Create Project api_response = api_instance.src_app_api_projects_create_project(project_create_schema) print("The response of DefaultApi->src_app_api_projects_create_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_create_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **project\_create\_schema** | [**ProjectCreateSchema**](/api-reference/rest/ProjectCreateSchema) | | | ### Return type [**ProjectSchema**](/api-reference/rest/ProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_create\_project\_link** > src\_app\_api\_projects\_create\_project\_link(uuid, link\_share\_create\_schema) Create Project Link Create a shareable link for a project. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.link_share_create_schema import LinkShareCreateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | link_share_create_schema = cyberwave.rest.LinkShareCreateSchema() # LinkShareCreateSchema | try: # Create Project Link api_instance.src_app_api_projects_create_project_link(uuid, link_share_create_schema) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_create_project_link: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | ---------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **link\_share\_create\_schema** | [**LinkShareCreateSchema**](/api-reference/rest/LinkShareCreateSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_delete\_project** > src\_app\_api\_projects\_delete\_project(uuid) Delete Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Project api_instance.src_app_api_projects_delete_project(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_delete_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_get\_my\_project\_permissions** > PermissionsSchema src\_app\_api\_projects\_get\_my\_project\_permissions(uuid) Get My Project Permissions Get current user's permissions on this project. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.permissions_schema import PermissionsSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get My Project Permissions api_response = api_instance.src_app_api_projects_get_my_project_permissions(uuid) print("The response of DefaultApi->src_app_api_projects_get_my_project_permissions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_get_my_project_permissions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**PermissionsSchema**](/api-reference/rest/PermissionsSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_get\_project** > ProjectSchema src\_app\_api\_projects\_get\_project(uuid) Get Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.project_schema import ProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Project api_response = api_instance.src_app_api_projects_get_project(uuid) print("The response of DefaultApi->src_app_api_projects_get_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_get_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**ProjectSchema**](/api-reference/rest/ProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_get\_project\_shares** > SharesResponseSchema src\_app\_api\_projects\_get\_project\_shares(uuid) Get Project Shares List all shares for a project. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.shares_response_schema import SharesResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Project Shares api_response = api_instance.src_app_api_projects_get_project_shares(uuid) print("The response of DefaultApi->src_app_api_projects_get_project_shares:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_get_project_shares: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**SharesResponseSchema**](/api-reference/rest/SharesResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_invite\_user\_to\_project** > Dict\[str, object] src\_app\_api\_projects\_invite\_user\_to\_project(uuid) Invite User To Project Invite a non-existent user to a project. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Invite User To Project api_response = api_instance.src_app_api_projects_invite_user_to_project(uuid) print("The response of DefaultApi->src_app_api_projects_invite_user_to_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_invite_user_to_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_list\_projects** > List\[ProjectSchema] src\_app\_api\_projects\_list\_projects() List Projects List all projects visible to the current user. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.project_schema import ProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Projects api_response = api_instance.src_app_api_projects_list_projects() print("The response of DefaultApi->src_app_api_projects_list_projects:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_list_projects: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[ProjectSchema\]**](/api-reference/rest/ProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_revoke\_project\_link** > src\_app\_api\_projects\_revoke\_project\_link(uuid, link\_share\_revoke\_schema) Revoke Project Link Revoke a shareable link. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.link_share_revoke_schema import LinkShareRevokeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | link_share_revoke_schema = cyberwave.rest.LinkShareRevokeSchema() # LinkShareRevokeSchema | try: # Revoke Project Link api_instance.src_app_api_projects_revoke_project_link(uuid, link_share_revoke_schema) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_revoke_project_link: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | ---------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **link\_share\_revoke\_schema** | [**LinkShareRevokeSchema**](/api-reference/rest/LinkShareRevokeSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_share\_project** > ProjectShareResponseSchema src\_app\_api\_projects\_share\_project(uuid, share\_schema) Share Project Share a project with a user or team. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.project_share_response_schema import ProjectShareResponseSchema from cyberwave.rest.models.share_schema import ShareSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | share_schema = cyberwave.rest.ShareSchema() # ShareSchema | try: # Share Project api_response = api_instance.src_app_api_projects_share_project(uuid, share_schema) print("The response of DefaultApi->src_app_api_projects_share_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_share_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | -------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **share\_schema** | [**ShareSchema**](/api-reference/rest/ShareSchema) | | | ### Return type [**ProjectShareResponseSchema**](/api-reference/rest/ProjectShareResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_unshare\_project** > ProjectShareResponseSchema src\_app\_api\_projects\_unshare\_project(uuid, share\_schema) Unshare Project Remove sharing permissions for a user or team. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.project_share_response_schema import ProjectShareResponseSchema from cyberwave.rest.models.share_schema import ShareSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | share_schema = cyberwave.rest.ShareSchema() # ShareSchema | try: # Unshare Project api_response = api_instance.src_app_api_projects_unshare_project(uuid, share_schema) print("The response of DefaultApi->src_app_api_projects_unshare_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_unshare_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | -------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **share\_schema** | [**ShareSchema**](/api-reference/rest/ShareSchema) | | | ### Return type [**ProjectShareResponseSchema**](/api-reference/rest/ProjectShareResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_projects\_update\_project** > ProjectSchema src\_app\_api\_projects\_update\_project(uuid, project\_create\_schema) Update Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.project_create_schema import ProjectCreateSchema from cyberwave.rest.models.project_schema import ProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | project_create_schema = cyberwave.rest.ProjectCreateSchema() # ProjectCreateSchema | try: # Update Project api_response = api_instance.src_app_api_projects_update_project(uuid, project_create_schema) print("The response of DefaultApi->src_app_api_projects_update_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_projects_update_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **project\_create\_schema** | [**ProjectCreateSchema**](/api-reference/rest/ProjectCreateSchema) | | | ### Return type [**ProjectSchema**](/api-reference/rest/ProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tagged\_frames\_create\_tagged\_frames** > TaggedFramesSchema src\_app\_api\_tagged\_frames\_create\_tagged\_frames(tagged\_frames\_create\_schema) Create Tagged Frames Create a new tagged frames entry. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.tagged_frames_create_schema import TaggedFramesCreateSchema from cyberwave.rest.models.tagged_frames_schema import TaggedFramesSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) tagged_frames_create_schema = cyberwave.rest.TaggedFramesCreateSchema() # TaggedFramesCreateSchema | try: # Create Tagged Frames api_response = api_instance.src_app_api_tagged_frames_create_tagged_frames(tagged_frames_create_schema) print("The response of DefaultApi->src_app_api_tagged_frames_create_tagged_frames:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tagged_frames_create_tagged_frames: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **tagged\_frames\_create\_schema** | [**TaggedFramesCreateSchema**](/api-reference/rest/TaggedFramesCreateSchema) | | | ### Return type [**TaggedFramesSchema**](/api-reference/rest/TaggedFramesSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tagged\_frames\_delete\_tagged\_frames** > src\_app\_api\_tagged\_frames\_delete\_tagged\_frames(uuid) Delete Tagged Frames Delete a tagged frames entry by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Tagged Frames api_instance.src_app_api_tagged_frames_delete_tagged_frames(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tagged_frames_delete_tagged_frames: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tagged\_frames\_get\_tagged\_frames** > TaggedFramesSchema src\_app\_api\_tagged\_frames\_get\_tagged\_frames(uuid) Get Tagged Frames Get a specific tagged frames by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.tagged_frames_schema import TaggedFramesSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Tagged Frames api_response = api_instance.src_app_api_tagged_frames_get_tagged_frames(uuid) print("The response of DefaultApi->src_app_api_tagged_frames_get_tagged_frames:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tagged_frames_get_tagged_frames: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**TaggedFramesSchema**](/api-reference/rest/TaggedFramesSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tagged\_frames\_list\_tagged\_frames** > List\[TaggedFramesSchema] src\_app\_api\_tagged\_frames\_list\_tagged\_frames(recording\_uuid=recording\_uuid) List Tagged Frames List all tagged frames accessible by the user. Optionally filter by recording\_uuid. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.tagged_frames_schema import TaggedFramesSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) recording_uuid = 'recording_uuid_example' # str | (optional) try: # List Tagged Frames api_response = api_instance.src_app_api_tagged_frames_list_tagged_frames(recording_uuid=recording_uuid) print("The response of DefaultApi->src_app_api_tagged_frames_list_tagged_frames:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tagged_frames_list_tagged_frames: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **recording\_uuid** | **str** | | \[optional] | ### Return type [**List\[TaggedFramesSchema\]**](/api-reference/rest/TaggedFramesSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tagged\_frames\_update\_tagged\_frames** > TaggedFramesSchema src\_app\_api\_tagged\_frames\_update\_tagged\_frames(uuid, tagged\_frames\_update\_schema) Update Tagged Frames Update an existing tagged frames entry. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.tagged_frames_schema import TaggedFramesSchema from cyberwave.rest.models.tagged_frames_update_schema import TaggedFramesUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | tagged_frames_update_schema = cyberwave.rest.TaggedFramesUpdateSchema() # TaggedFramesUpdateSchema | try: # Update Tagged Frames api_response = api_instance.src_app_api_tagged_frames_update_tagged_frames(uuid, tagged_frames_update_schema) print("The response of DefaultApi->src_app_api_tagged_frames_update_tagged_frames:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tagged_frames_update_tagged_frames: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **tagged\_frames\_update\_schema** | [**TaggedFramesUpdateSchema**](/api-reference/rest/TaggedFramesUpdateSchema) | | | ### Return type [**TaggedFramesSchema**](/api-reference/rest/TaggedFramesSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_cancel\_task\_execution** > src\_app\_api\_tasks\_cancel\_task\_execution(uuid) Cancel Task Execution Cancel a task execution. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Cancel Task Execution api_instance.src_app_api_tasks_cancel_task_execution(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_cancel_task_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_create\_task** > TaskSchema src\_app\_api\_tasks\_create\_task(create\_task\_schema) Create Task Create a reusable task definition. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.create_task_schema import CreateTaskSchema from cyberwave.rest.models.task_schema import TaskSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) create_task_schema = cyberwave.rest.CreateTaskSchema() # CreateTaskSchema | try: # Create Task api_response = api_instance.src_app_api_tasks_create_task(create_task_schema) print("The response of DefaultApi->src_app_api_tasks_create_task:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_create_task: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------------------------------------------------------ | ----------- | ----- | | **create\_task\_schema** | [**CreateTaskSchema**](/api-reference/rest/CreateTaskSchema) | | | ### Return type [**TaskSchema**](/api-reference/rest/TaskSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_delete\_task** > src\_app\_api\_tasks\_delete\_task(uuid) Delete Task Delete a task. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Task api_instance.src_app_api_tasks_delete_task(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_delete_task: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_execute\_task** > TaskExecutionSchema src\_app\_api\_tasks\_execute\_task(uuid, execute\_task\_schema) Execute Task Execute a task on a twin (standalone, not part of mission). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.execute_task_schema import ExecuteTaskSchema from cyberwave.rest.models.task_execution_schema import TaskExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | execute_task_schema = cyberwave.rest.ExecuteTaskSchema() # ExecuteTaskSchema | try: # Execute Task api_response = api_instance.src_app_api_tasks_execute_task(uuid, execute_task_schema) print("The response of DefaultApi->src_app_api_tasks_execute_task:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_execute_task: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------- | -------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **execute\_task\_schema** | [**ExecuteTaskSchema**](/api-reference/rest/ExecuteTaskSchema) | | | ### Return type [**TaskExecutionSchema**](/api-reference/rest/TaskExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_get\_task** > TaskSchema src\_app\_api\_tasks\_get\_task(uuid) Get Task Get a task by UUID. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.task_schema import TaskSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Task api_response = api_instance.src_app_api_tasks_get_task(uuid) print("The response of DefaultApi->src_app_api_tasks_get_task:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_get_task: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**TaskSchema**](/api-reference/rest/TaskSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_get\_task\_execution** > TaskExecutionSchema src\_app\_api\_tasks\_get\_task\_execution(uuid) Get Task Execution ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.task_execution_schema import TaskExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Task Execution api_response = api_instance.src_app_api_tasks_get_task_execution(uuid) print("The response of DefaultApi->src_app_api_tasks_get_task_execution:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_get_task_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**TaskExecutionSchema**](/api-reference/rest/TaskExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_list\_task\_queue** > List\[TaskExecutionSchema] src\_app\_api\_tasks\_list\_task\_queue(status=status, environment\_uuid=environment\_uuid, twin\_uuid=twin\_uuid, task\_type=task\_type, limit=limit) List Task Queue List task executions (the order queue). Filters: * status: Filter by status (pending, queued, running, completed, failed, cancelled) Can be comma-separated for multiple: "pending,queued,running" * environment\_uuid: Filter by environment * twin\_uuid: Filter by specific twin * task\_type: Filter by task type (navigation, motion, mlmodel) * limit: Max results (default 100) Examples: * GET /tasks/queue?status=pending,queued,running (active queue) * GET /tasks/queue?status=running (currently executing) * GET /tasks/queue?environment\_uuid=xxx\&status=pending ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.task_execution_schema import TaskExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) status = 'status_example' # str | (optional) environment_uuid = 'environment_uuid_example' # str | (optional) twin_uuid = 'twin_uuid_example' # str | (optional) task_type = 'task_type_example' # str | (optional) limit = 100 # int | (optional) (default to 100) try: # List Task Queue api_response = api_instance.src_app_api_tasks_list_task_queue(status=status, environment_uuid=environment_uuid, twin_uuid=twin_uuid, task_type=task_type, limit=limit) print("The response of DefaultApi->src_app_api_tasks_list_task_queue:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_list_task_queue: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------- | ------- | ----------- | ----------------------------- | | **status** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **twin\_uuid** | **str** | | \[optional] | | **task\_type** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**List\[TaskExecutionSchema\]**](/api-reference/rest/TaskExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_list\_tasks** > List\[TaskSchema] src\_app\_api\_tasks\_list\_tasks(workspace\_uuid=workspace\_uuid, task\_type=task\_type) List Tasks List tasks in workspace. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.task_schema import TaskSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) workspace_uuid = 'workspace_uuid_example' # str | (optional) task_type = 'task_type_example' # str | (optional) try: # List Tasks api_response = api_instance.src_app_api_tasks_list_tasks(workspace_uuid=workspace_uuid, task_type=task_type) print("The response of DefaultApi->src_app_api_tasks_list_tasks:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_list_tasks: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------- | | **workspace\_uuid** | **str** | | \[optional] | | **task\_type** | **str** | | \[optional] | ### Return type [**List\[TaskSchema\]**](/api-reference/rest/TaskSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_tasks\_update\_task** > TaskSchema src\_app\_api\_tasks\_update\_task(uuid, update\_task\_schema) Update Task Update a task. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.task_schema import TaskSchema from cyberwave.rest.models.update_task_schema import UpdateTaskSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | update_task_schema = cyberwave.rest.UpdateTaskSchema() # UpdateTaskSchema | try: # Update Task api_response = api_instance.src_app_api_tasks_update_task(uuid, update_task_schema) print("The response of DefaultApi->src_app_api_tasks_update_task:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_tasks_update_task: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **update\_task\_schema** | [**UpdateTaskSchema**](/api-reference/rest/UpdateTaskSchema) | | | ### Return type [**TaskSchema**](/api-reference/rest/TaskSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_create\_twin** > TwinSchema src\_app\_api\_twins\_create\_twin(twin\_create\_schema) Create Twin ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_create_schema import TwinCreateSchema from cyberwave.rest.models.twin_schema import TwinSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_create_schema = cyberwave.rest.TwinCreateSchema() # TwinCreateSchema | try: # Create Twin api_response = api_instance.src_app_api_twins_create_twin(twin_create_schema) print("The response of DefaultApi->src_app_api_twins_create_twin:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_create_twin: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------------------------------------------------------ | ----------- | ----- | | **twin\_create\_schema** | [**TwinCreateSchema**](/api-reference/rest/TwinCreateSchema) | | | ### Return type [**TwinSchema**](/api-reference/rest/TwinSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_delete\_twin** > src\_app\_api\_twins\_delete\_twin(uuid) Delete Twin ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Twin api_instance.src_app_api_twins_delete_twin(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_delete_twin: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_execute\_twin\_action** > TwinActionResponseSchema src\_app\_api\_twins\_execute\_twin\_action(uuid, twin\_action\_request\_schema) Execute Twin Action ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_action_request_schema import TwinActionRequestSchema from cyberwave.rest.models.twin_action_response_schema import TwinActionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_action_request_schema = cyberwave.rest.TwinActionRequestSchema() # TwinActionRequestSchema | try: # Execute Twin Action api_response = api_instance.src_app_api_twins_execute_twin_action(uuid, twin_action_request_schema) print("The response of DefaultApi->src_app_api_twins_execute_twin_action:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_execute_twin_action: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_action\_request\_schema** | [**TwinActionRequestSchema**](/api-reference/rest/TwinActionRequestSchema) | | | ### Return type [**TwinActionResponseSchema**](/api-reference/rest/TwinActionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_recording** > TwinConnectionEventSchema src\_app\_api\_twins\_get\_recording(recording\_uuid) Get Recording Get a specific recording by UUID. Returns TWIN\_RECORDING\_INFO event with full metadata. Includes signed\_url for mp4\_path if available. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_connection_event_schema import TwinConnectionEventSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) recording_uuid = 'recording_uuid_example' # str | try: # Get Recording api_response = api_instance.src_app_api_twins_get_recording(recording_uuid) print("The response of DefaultApi->src_app_api_twins_get_recording:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_recording: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **recording\_uuid** | **str** | | | ### Return type [**TwinConnectionEventSchema**](/api-reference/rest/TwinConnectionEventSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin** > TwinSchema src\_app\_api\_twins\_get\_twin(uuid) Get Twin ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_schema import TwinSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin api_response = api_instance.src_app_api_twins_get_twin(uuid) print("The response of DefaultApi->src_app_api_twins_get_twin:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**TwinSchema**](/api-reference/rest/TwinSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_action\_status** > TwinActionStatusSchema src\_app\_api\_twins\_get\_twin\_action\_status(uuid, action\_id) Get Twin Action Status ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_action_status_schema import TwinActionStatusSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | action_id = 'action_id_example' # str | try: # Get Twin Action Status api_response = api_instance.src_app_api_twins_get_twin_action_status(uuid, action_id) print("The response of DefaultApi->src_app_api_twins_get_twin_action_status:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_action_status: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **action\_id** | **str** | | | ### Return type [**TwinActionStatusSchema**](/api-reference/rest/TwinActionStatusSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_calibration** > TwinJointCalibrationSchema src\_app\_api\_twins\_get\_twin\_calibration(uuid) Get Twin Calibration ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_joint_calibration_schema import TwinJointCalibrationSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Calibration api_response = api_instance.src_app_api_twins_get_twin_calibration(uuid) print("The response of DefaultApi->src_app_api_twins_get_twin_calibration:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_calibration: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**TwinJointCalibrationSchema**](/api-reference/rest/TwinJointCalibrationSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_connection\_history** > List\[TwinConnectionEventSchema] src\_app\_api\_twins\_get\_twin\_connection\_history(uuid, limit=limit) Get Twin Connection History Get the connection history for a twin. Returns recent telemetry events like connected, disconnected, telemetry\_start, telemetry\_end. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_connection_event_schema import TwinConnectionEventSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | limit = 20 # int | (optional) (default to 20) try: # Get Twin Connection History api_response = api_instance.src_app_api_twins_get_twin_connection_history(uuid, limit=limit) print("The response of DefaultApi->src_app_api_twins_get_twin_connection_history:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_connection_history: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | | | **limit** | **int** | | \[optional] \[default to 20] | ### Return type [**List\[TwinConnectionEventSchema\]**](/api-reference/rest/TwinConnectionEventSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_driver\_logs** > TwinDriverLogsResponseSchema src\_app\_api\_twins\_get\_twin\_driver\_logs(uuid, limit=limit, offset=offset) Get Twin Driver Logs Get persisted driver logs for a twin, newest-first. Query params: * limit: max rows to return (default 100, max 500) * offset: number of rows to skip (default 0) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_driver_logs_response_schema import TwinDriverLogsResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | limit = 100 # int | (optional) (default to 100) offset = 0 # int | (optional) (default to 0) try: # Get Twin Driver Logs api_response = api_instance.src_app_api_twins_get_twin_driver_logs(uuid, limit=limit, offset=offset) print("The response of DefaultApi->src_app_api_twins_get_twin_driver_logs:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_driver_logs: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------- | ------- | ----------- | ----------------------------- | | **uuid** | **str** | | | | **limit** | **int** | | \[optional] \[default to 100] | | **offset** | **int** | | \[optional] \[default to 0] | ### Return type [**TwinDriverLogsResponseSchema**](/api-reference/rest/TwinDriverLogsResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_latest\_frame** > src\_app\_api\_twins\_get\_twin\_latest\_frame(uuid, mock=mock) Get Twin Latest Frame Get the latest frame from a twin's camera stream. Serves the frame directly from Redis without saving to permanent storage. For multi-camera twins, the media service stores frames with key `frame:{twin*uuid}*{sensor_id}:rgb:latest`. Pass ?sensor\_id=wrist\_camera to get a specific camera. Query params: * mock: if true, return a deterministic mock JPEG payload. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | mock = False # bool | (optional) (default to False) try: # Get Twin Latest Frame api_instance.src_app_api_twins_get_twin_latest_frame(uuid, mock=mock) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_latest_frame: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | -------- | ----------- | ------------------------------- | | **uuid** | **str** | | | | **mock** | **bool** | | \[optional] \[default to False] | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_latest\_metrics** > src\_app\_api\_twins\_get\_twin\_latest\_metrics(uuid) Get Twin Latest Metrics Get the latest metrics snapshot for a twin. Returns the most recent metrics from Twin.metadata (current state) plus the timestamp of the last update. This is more efficient than querying historical data when you only need the current state. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Latest Metrics api_instance.src_app_api_twins_get_twin_latest_metrics(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_latest_metrics: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_links** > List\[Optional\[str]] src\_app\_api\_twins\_get\_twin\_links(uuid) Get Twin Links Get list of available links in a twin's schema for docking. Returns a list of link names that can be used as attachment points when docking other twins to this twin. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Links api_response = api_instance.src_app_api_twins_get_twin_links(uuid) print("The response of DefaultApi->src_app_api_twins_get_twin_links:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_links: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **List\[Optional\[str]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_metrics** > List\[TwinMetricsQuerySchema] src\_app\_api\_twins\_get\_twin\_metrics(uuid, start=start, end=end, limit=limit) Get Twin Metrics Get historical metrics for a twin. Returns time-series metrics data (battery level, navigation status, etc.) logged via MQTT from edge devices. Args: uuid: Twin UUID start: Start datetime (ISO format, e.g., "2026-01-01T00:00:00Z") end: End datetime (ISO format) limit: Max results (default 100, max 1000) Returns: List of metrics snapshots ordered by timestamp (newest first) Examples: GET `/twins/{uuid}/metrics` GET `/twins/{uuid}/metrics?start=2026-01-20T00:00:00Z&limit=500` GET `/twins/{uuid}/metrics?start=2026-01-01&end=2026-01-21` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_metrics_query_schema import TwinMetricsQuerySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | start = 'start_example' # str | (optional) end = 'end_example' # str | (optional) limit = 100 # int | (optional) (default to 100) try: # Get Twin Metrics api_response = api_instance.src_app_api_twins_get_twin_metrics(uuid, start=start, end=end, limit=limit) print("The response of DefaultApi->src_app_api_twins_get_twin_metrics:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_metrics: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------- | ------- | ----------- | ----------------------------- | | **uuid** | **str** | | | | **start** | **str** | | \[optional] | | **end** | **str** | | \[optional] | | **limit** | **int** | | \[optional] \[default to 100] | ### Return type [**List\[TwinMetricsQuerySchema\]**](/api-reference/rest/TwinMetricsQuerySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_motions** > TwinMotionResponseSchema src\_app\_api\_twins\_get\_twin\_motions(uuid, environment\_uuid=environment\_uuid) Get Twin Motions ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_motion_response_schema import TwinMotionResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | environment_uuid = 'environment_uuid_example' # str | (optional) try: # Get Twin Motions api_response = api_instance.src_app_api_twins_get_twin_motions(uuid, environment_uuid=environment_uuid) print("The response of DefaultApi->src_app_api_twins_get_twin_motions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_motions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------- | ------- | ----------- | ----------- | | **uuid** | **str** | | | | **environment\_uuid** | **str** | | \[optional] | ### Return type [**TwinMotionResponseSchema**](/api-reference/rest/TwinMotionResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_notebook** > src\_app\_api\_twins\_get\_twin\_notebook(uuid) Get Twin Notebook Generate and serve a Jupyter notebook for this twin. This endpoint is public so Google Colab can fetch it directly. Usage: `https://colab.research.google.com/#fileId=/twins/{uuid}/notebook.ipynb` ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Notebook api_instance.src_app_api_twins_get_twin_notebook(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_notebook: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_recordings** > List\[TwinConnectionEventSchema] src\_app\_api\_twins\_get\_twin\_recordings(uuid) Get Twin Recordings Get all recordings for a twin. Returns TWIN\_RECORDING\_INFO events (parquet recordings) for camera twins. Only returns recordings that have mp4\_path (camera recordings). Includes signed\_url in metadata for each recording. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_connection_event_schema import TwinConnectionEventSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Recordings api_response = api_instance.src_app_api_twins_get_twin_recordings(uuid) print("The response of DefaultApi->src_app_api_twins_get_twin_recordings:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_recordings: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[TwinConnectionEventSchema\]**](/api-reference/rest/TwinConnectionEventSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_get\_twin\_universal\_schema\_at\_path** > Dict\[str, object] src\_app\_api\_twins\_get\_twin\_universal\_schema\_at\_path(uuid, path=path) Get Twin Universal Schema At Path Get value at a specific JSON Pointer path in the twin's universal schema. Query params: path: JSON Pointer path (e.g., /sensors/0, /extensions/cyberwave/capabilities) Returns: `{"path": "...", "value": }` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | path = '' # str | (optional) (default to '') try: # Get Twin Universal Schema At Path api_response = api_instance.src_app_api_twins_get_twin_universal_schema_at_path(uuid, path=path) print("The response of DefaultApi->src_app_api_twins_get_twin_universal_schema_at_path:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_get_twin_universal_schema_at_path: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | | | **path** | **str** | | \[optional] \[default to ''] | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_link\_occupancy\_map** > src\_app\_api\_twins\_link\_occupancy\_map(uuid, occupancy\_map\_create\_schema) Link Occupancy Map Link an occupancy-grid map to this twin, compute (or retrieve) the world->map transform, and send it to the edge via MQTT. The map must have been uploaded beforehand via `POST /maps` (with `map_type=occupancy_grid`). Flow: 1. Validate and associate the map with the twin. 2. If the environment already has a manually-set navigation transform, use it. Otherwise, attempt to auto-align the SLAM map with the 3D scene (currently mocked as identity). 3. Save the transform into `environment.settings.navigation`. 4. Publish the transform on the `occupancy-map-tf` MQTT topic so the edge waypoint bridge sets its `world -> map` TF. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.occupancy_map_create_schema import OccupancyMapCreateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | occupancy_map_create_schema = cyberwave.rest.OccupancyMapCreateSchema() # OccupancyMapCreateSchema | try: # Link Occupancy Map api_instance.src_app_api_twins_link_occupancy_map(uuid, occupancy_map_create_schema) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_link_occupancy_map: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **occupancy\_map\_create\_schema** | [**OccupancyMapCreateSchema**](/api-reference/rest/OccupancyMapCreateSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_list\_all\_twins** > List\[TwinSchema] src\_app\_api\_twins\_list\_all\_twins() List All Twins ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_schema import TwinSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List All Twins api_response = api_instance.src_app_api_twins_list_all_twins() print("The response of DefaultApi->src_app_api_twins_list_all_twins:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_list_all_twins: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[TwinSchema\]**](/api-reference/rest/TwinSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_patch\_twin\_universal\_schema** > Dict\[str, object] src\_app\_api\_twins\_patch\_twin\_universal\_schema(uuid, twin\_universal\_schema\_patch\_schema) Patch Twin Universal Schema Update the twin's universal schema using JSON Pointer operations. This allows editing twin-specific schema overrides, such as: * /sensors (array of sensor objects) * /extensions/cyberwave/capabilities Note: Unlike Asset schema, Twin schema PATCH does NOT update a hash (twin schema is a snapshot, not authoritative). Body: ```json theme={null} { "op": "add" | "replace", "path": "/sensors/0/parameters/id", "value": "my_camera" } ``` Returns: ```json theme={null} { "schema": "", "updated": { "op": "...", "path": "..." } } ``` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_universal_schema_patch_schema import TwinUniversalSchemaPatchSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_universal_schema_patch_schema = cyberwave.rest.TwinUniversalSchemaPatchSchema() # TwinUniversalSchemaPatchSchema | try: # Patch Twin Universal Schema api_response = api_instance.src_app_api_twins_patch_twin_universal_schema(uuid, twin_universal_schema_patch_schema) print("The response of DefaultApi->src_app_api_twins_patch_twin_universal_schema:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_patch_twin_universal_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------------ | ---------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_universal\_schema\_patch\_schema** | [**TwinUniversalSchemaPatchSchema**](/api-reference/rest/TwinUniversalSchemaPatchSchema) | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_reload\_twin\_capabilities** > Dict\[str, object] src\_app\_api\_twins\_reload\_twin\_capabilities(uuid) Reload Twin Capabilities Get capabilities from Twin.universal\_schema. Note: Capabilities are now derived from schema only, not cached in DB. This endpoint is kept for backward compatibility. Returns: ``` {"success": true, "capabilities": {...}} ``` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Reload Twin Capabilities api_response = api_instance.src_app_api_twins_reload_twin_capabilities(uuid) print("The response of DefaultApi->src_app_api_twins_reload_twin_capabilities:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_reload_twin_capabilities: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_reload\_twins\_capabilities\_bulk** > Dict\[str, object] src\_app\_api\_twins\_reload\_twins\_capabilities\_bulk(reload\_capabilities\_bulk\_schema) Reload Twins Capabilities Bulk Bulk reload capabilities for multiple twins. Filters: * environment\_uuid: Reload all twins in an environment * twin\_uuids: Reload specific twins by UUID If both are provided, twins must match both criteria. If neither is provided, returns error. Returns: ``` {"success": true, "updated_count": N, "failed_count": M, "errors": [...]} ``` ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.reload_capabilities_bulk_schema import ReloadCapabilitiesBulkSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) reload_capabilities_bulk_schema = cyberwave.rest.ReloadCapabilitiesBulkSchema() # ReloadCapabilitiesBulkSchema | try: # Reload Twins Capabilities Bulk api_response = api_instance.src_app_api_twins_reload_twins_capabilities_bulk(reload_capabilities_bulk_schema) print("The response of DefaultApi->src_app_api_twins_reload_twins_capabilities_bulk:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_reload_twins_capabilities_bulk: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------------- | ------------------------------------------------------------------------------------ | ----------- | ----- | | **reload\_capabilities\_bulk\_schema** | [**ReloadCapabilitiesBulkSchema**](/api-reference/rest/ReloadCapabilitiesBulkSchema) | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_sync\_twin\_with\_asset** > SyncWithAssetSchema src\_app\_api\_twins\_sync\_twin\_with\_asset(uuid) Sync Twin With Asset Sync twin metadata and universal\_schema with its parent asset. This updates the twin's metadata with the latest values from the asset for fields that are typically defined at the asset level (like locomotion\_animations). Fields that are twin-specific (like controller assignments) are preserved. Note: This also re-snapshots the twin's universal\_schema from the asset, overwriting any twin-specific schema edits made via PATCH `/api/v1/twins/{uuid}/universal-schema`. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.sync_with_asset_schema import SyncWithAssetSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Sync Twin With Asset api_response = api_instance.src_app_api_twins_sync_twin_with_asset(uuid) print("The response of DefaultApi->src_app_api_twins_sync_twin_with_asset:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_sync_twin_with_asset: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**SyncWithAssetSchema**](/api-reference/rest/SyncWithAssetSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_update\_twin** > TwinSchema src\_app\_api\_twins\_update\_twin(uuid, twin\_create\_schema) Update Twin Update a twin's properties. Note: When changing the asset\_uuid, the twin's universal\_schema will be re-snapshotted from the new asset, overwriting any twin-specific schema edits made via PATCH `/api/v1/twins/{uuid}/universal-schema`. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_create_schema import TwinCreateSchema from cyberwave.rest.models.twin_schema import TwinSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_create_schema = cyberwave.rest.TwinCreateSchema() # TwinCreateSchema | try: # Update Twin api_response = api_instance.src_app_api_twins_update_twin(uuid, twin_create_schema) print("The response of DefaultApi->src_app_api_twins_update_twin:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_update_twin: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------ | ------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **twin\_create\_schema** | [**TwinCreateSchema**](/api-reference/rest/TwinCreateSchema) | | | ### Return type [**TwinSchema**](/api-reference/rest/TwinSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_update\_twin\_calibration** > TwinJointCalibrationSchema src\_app\_api\_twins\_update\_twin\_calibration(uuid, twin\_joint\_calibration\_schema) Update Twin Calibration ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_joint_calibration_schema import TwinJointCalibrationSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_joint_calibration_schema = cyberwave.rest.TwinJointCalibrationSchema() # TwinJointCalibrationSchema | try: # Update Twin Calibration api_response = api_instance.src_app_api_twins_update_twin_calibration(uuid, twin_joint_calibration_schema) print("The response of DefaultApi->src_app_api_twins_update_twin_calibration:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_update_twin_calibration: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------------ | -------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_joint\_calibration\_schema** | [**TwinJointCalibrationSchema**](/api-reference/rest/TwinJointCalibrationSchema) | | | ### Return type [**TwinJointCalibrationSchema**](/api-reference/rest/TwinJointCalibrationSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_twins\_update\_twin\_state** > TwinSchema src\_app\_api\_twins\_update\_twin\_state(uuid, twin\_state\_update\_schema) Update Twin State ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.twin_schema import TwinSchema from cyberwave.rest.models.twin_state_update_schema import TwinStateUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | twin_state_update_schema = cyberwave.rest.TwinStateUpdateSchema() # TwinStateUpdateSchema | try: # Update Twin State api_response = api_instance.src_app_api_twins_update_twin_state(uuid, twin_state_update_schema) print("The response of DefaultApi->src_app_api_twins_update_twin_state:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_twins_update_twin_state: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------------- | ---------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_state\_update\_schema** | [**TwinStateUpdateSchema**](/api-reference/rest/TwinStateUpdateSchema) | | | ### Return type [**TwinSchema**](/api-reference/rest/TwinSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_create\_urdf\_project** > URDFProjectSchema src\_app\_api\_urdf\_create\_urdf\_project(urdf\_project\_create\_schema) Create Urdf Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.urdf_project_create_schema import URDFProjectCreateSchema from cyberwave.rest.models.urdf_project_schema import URDFProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) urdf_project_create_schema = cyberwave.rest.URDFProjectCreateSchema() # URDFProjectCreateSchema | try: # Create Urdf Project api_response = api_instance.src_app_api_urdf_create_urdf_project(urdf_project_create_schema) print("The response of DefaultApi->src_app_api_urdf_create_urdf_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_create_urdf_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **urdf\_project\_create\_schema** | [**URDFProjectCreateSchema**](/api-reference/rest/URDFProjectCreateSchema) | | | ### Return type [**URDFProjectSchema**](/api-reference/rest/URDFProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_delete\_urdf\_project** > src\_app\_api\_urdf\_delete\_urdf\_project(uuid) Delete Urdf Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Urdf Project api_instance.src_app_api_urdf_delete_urdf_project(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_delete_urdf_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_fix\_urdf\_project\_slug** > URDFProjectSchema src\_app\_api\_urdf\_fix\_urdf\_project\_slug(uuid, new\_slug, new\_main\_file\_path) Fix Urdf Project Slug Fix a URDF project's slug and main\_file\_path to match actual storage. This is useful when files exist in storage but the DB record points to the wrong location. Requires staff/superuser permissions. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.urdf_project_schema import URDFProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | new_slug = 'new_slug_example' # str | new_main_file_path = 'new_main_file_path_example' # str | try: # Fix Urdf Project Slug api_response = api_instance.src_app_api_urdf_fix_urdf_project_slug(uuid, new_slug, new_main_file_path) print("The response of DefaultApi->src_app_api_urdf_fix_urdf_project_slug:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_fix_urdf_project_slug: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **new\_slug** | **str** | | | | **new\_main\_file\_path** | **str** | | | ### Return type [**URDFProjectSchema**](/api-reference/rest/URDFProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_get\_twin\_joint\_state** > JointStateSchema src\_app\_api\_urdf\_get\_twin\_joint\_state(uuid, joint\_name) Get Twin Joint State ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.joint_state_schema import JointStateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | joint_name = 'joint_name_example' # str | try: # Get Twin Joint State api_response = api_instance.src_app_api_urdf_get_twin_joint_state(uuid, joint_name) print("The response of DefaultApi->src_app_api_urdf_get_twin_joint_state:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_get_twin_joint_state: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **joint\_name** | **str** | | | ### Return type [**JointStateSchema**](/api-reference/rest/JointStateSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_get\_twin\_joint\_states** > JointStatesSchema src\_app\_api\_urdf\_get\_twin\_joint\_states(uuid) Get Twin Joint States ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.joint_states_schema import JointStatesSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Joint States api_response = api_instance.src_app_api_urdf_get_twin_joint_states(uuid) print("The response of DefaultApi->src_app_api_urdf_get_twin_joint_states:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_get_twin_joint_states: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**JointStatesSchema**](/api-reference/rest/JointStatesSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_get\_twin\_joints** > List\[JointSchema] src\_app\_api\_urdf\_get\_twin\_joints(uuid) Get Twin Joints ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.joint_schema import JointSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Joints api_response = api_instance.src_app_api_urdf_get_twin_joints(uuid) print("The response of DefaultApi->src_app_api_urdf_get_twin_joints:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_get_twin_joints: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[JointSchema\]**](/api-reference/rest/JointSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_get\_twin\_robot\_description** > RobotDescriptionSchema src\_app\_api\_urdf\_get\_twin\_robot\_description(uuid) Get Twin Robot Description ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.robot_description_schema import RobotDescriptionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Robot Description api_response = api_instance.src_app_api_urdf_get_twin_robot_description(uuid) print("The response of DefaultApi->src_app_api_urdf_get_twin_robot_description:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_get_twin_robot_description: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**RobotDescriptionSchema**](/api-reference/rest/RobotDescriptionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_get\_twin\_urdf\_raw** > str src\_app\_api\_urdf\_get\_twin\_urdf\_raw(uuid) Get Twin Urdf Raw ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Twin Urdf Raw api_response = api_instance.src_app_api_urdf_get_twin_urdf_raw(uuid) print("The response of DefaultApi->src_app_api_urdf_get_twin_urdf_raw:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_get_twin_urdf_raw: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **str** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_get\_urdf\_project** > URDFProjectSchema src\_app\_api\_urdf\_get\_urdf\_project(uuid) Get Urdf Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.urdf_project_schema import URDFProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Urdf Project api_response = api_instance.src_app_api_urdf_get_urdf_project(uuid) print("The response of DefaultApi->src_app_api_urdf_get_urdf_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_get_urdf_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**URDFProjectSchema**](/api-reference/rest/URDFProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_list\_urdf\_projects** > List\[URDFProjectSchema] src\_app\_api\_urdf\_list\_urdf\_projects() List Urdf Projects ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.urdf_project_schema import URDFProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Urdf Projects api_response = api_instance.src_app_api_urdf_list_urdf_projects() print("The response of DefaultApi->src_app_api_urdf_list_urdf_projects:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_list_urdf_projects: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[URDFProjectSchema\]**](/api-reference/rest/URDFProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_update\_twin\_joint\_state** > JointStateSchema src\_app\_api\_urdf\_update\_twin\_joint\_state(uuid, joint\_name, joint\_state\_update\_schema) Update Twin Joint State ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.joint_state_schema import JointStateSchema from cyberwave.rest.models.joint_state_update_schema import JointStateUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | joint_name = 'joint_name_example' # str | joint_state_update_schema = cyberwave.rest.JointStateUpdateSchema() # JointStateUpdateSchema | try: # Update Twin Joint State api_response = api_instance.src_app_api_urdf_update_twin_joint_state(uuid, joint_name, joint_state_update_schema) print("The response of DefaultApi->src_app_api_urdf_update_twin_joint_state:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_update_twin_joint_state: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ------------------------------------------------------------------------ | ----------- | ----- | | **uuid** | **str** | | | | **joint\_name** | **str** | | | | **joint\_state\_update\_schema** | [**JointStateUpdateSchema**](/api-reference/rest/JointStateUpdateSchema) | | | ### Return type [**JointStateSchema**](/api-reference/rest/JointStateSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_update\_twin\_joint\_states** > JointStatesSchema src\_app\_api\_urdf\_update\_twin\_joint\_states(uuid, bulk\_joint\_states\_update\_schema) Update Twin Joint States ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.bulk_joint_states_update_schema import BulkJointStatesUpdateSchema from cyberwave.rest.models.joint_states_schema import JointStatesSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | bulk_joint_states_update_schema = cyberwave.rest.BulkJointStatesUpdateSchema() # BulkJointStatesUpdateSchema | try: # Update Twin Joint States api_response = api_instance.src_app_api_urdf_update_twin_joint_states(uuid, bulk_joint_states_update_schema) print("The response of DefaultApi->src_app_api_urdf_update_twin_joint_states:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_update_twin_joint_states: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------------- | ---------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **bulk\_joint\_states\_update\_schema** | [**BulkJointStatesUpdateSchema**](/api-reference/rest/BulkJointStatesUpdateSchema) | | | ### Return type [**JointStatesSchema**](/api-reference/rest/JointStatesSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_update\_urdf\_project** > URDFProjectSchema src\_app\_api\_urdf\_update\_urdf\_project(uuid, urdf\_project\_create\_schema) Update Urdf Project ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.urdf_project_create_schema import URDFProjectCreateSchema from cyberwave.rest.models.urdf_project_schema import URDFProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | urdf_project_create_schema = cyberwave.rest.URDFProjectCreateSchema() # URDFProjectCreateSchema | try: # Update Urdf Project api_response = api_instance.src_app_api_urdf_update_urdf_project(uuid, urdf_project_create_schema) print("The response of DefaultApi->src_app_api_urdf_update_urdf_project:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_update_urdf_project: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **urdf\_project\_create\_schema** | [**URDFProjectCreateSchema**](/api-reference/rest/URDFProjectCreateSchema) | | | ### Return type [**URDFProjectSchema**](/api-reference/rest/URDFProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_urdf\_upload\_zip\_file** > URDFProjectSchema src\_app\_api\_urdf\_upload\_zip\_file(uuid, file) Upload Zip File ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.urdf_project_schema import URDFProjectSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | file = None # bytearray | try: # Upload Zip File api_response = api_instance.src_app_api_urdf_upload_zip_file(uuid, file) print("The response of DefaultApi->src_app_api_urdf_upload_zip_file:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_urdf_upload_zip_file: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------------- | ----------- | ----- | | **uuid** | **str** | | | | **file** | **bytearray** | | | ### Return type [**URDFProjectSchema**](/api-reference/rest/URDFProjectSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: multipart/form-data * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_activate\_workflow** > WorkflowSchema src\_app\_api\_workflows\_activate\_workflow(uuid) Activate Workflow Activate a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_schema import WorkflowSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Activate Workflow api_response = api_instance.src_app_api_workflows_activate_workflow(uuid) print("The response of DefaultApi->src_app_api_workflows_activate_workflow:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_activate_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**WorkflowSchema**](/api-reference/rest/WorkflowSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_cancel\_workflow\_execution** > WorkflowExecutionSchema src\_app\_api\_workflows\_cancel\_workflow\_execution(execution\_uuid) Cancel Workflow Execution Cancel a running workflow execution. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_execution_schema import WorkflowExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) execution_uuid = 'execution_uuid_example' # str | try: # Cancel Workflow Execution api_response = api_instance.src_app_api_workflows_cancel_workflow_execution(execution_uuid) print("The response of DefaultApi->src_app_api_workflows_cancel_workflow_execution:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_cancel_workflow_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **execution\_uuid** | **str** | | | ### Return type [**WorkflowExecutionSchema**](/api-reference/rest/WorkflowExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_create\_workflow** > WorkflowSchema src\_app\_api\_workflows\_create\_workflow(workflow\_create\_schema) Create Workflow Create a new workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_create_schema import WorkflowCreateSchema from cyberwave.rest.models.workflow_schema import WorkflowSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) workflow_create_schema = cyberwave.rest.WorkflowCreateSchema() # WorkflowCreateSchema | try: # Create Workflow api_response = api_instance.src_app_api_workflows_create_workflow(workflow_create_schema) print("The response of DefaultApi->src_app_api_workflows_create_workflow:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_create_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------- | -------------------------------------------------------------------- | ----------- | ----- | | **workflow\_create\_schema** | [**WorkflowCreateSchema**](/api-reference/rest/WorkflowCreateSchema) | | | ### Return type [**WorkflowSchema**](/api-reference/rest/WorkflowSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_create\_workflow\_connection** > WorkflowConnectionSchema src\_app\_api\_workflows\_create\_workflow\_connection(uuid, workflow\_connection\_create\_schema) Create Workflow Connection Create a new connection between nodes. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_connection_create_schema import WorkflowConnectionCreateSchema from cyberwave.rest.models.workflow_connection_schema import WorkflowConnectionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workflow_connection_create_schema = cyberwave.rest.WorkflowConnectionCreateSchema() # WorkflowConnectionCreateSchema | try: # Create Workflow Connection api_response = api_instance.src_app_api_workflows_create_workflow_connection(uuid, workflow_connection_create_schema) print("The response of DefaultApi->src_app_api_workflows_create_workflow_connection:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_create_workflow_connection: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------------- | ---------------------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workflow\_connection\_create\_schema** | [**WorkflowConnectionCreateSchema**](/api-reference/rest/WorkflowConnectionCreateSchema) | | | ### Return type [**WorkflowConnectionSchema**](/api-reference/rest/WorkflowConnectionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_create\_workflow\_node** > WorkflowNodeSchema src\_app\_api\_workflows\_create\_workflow\_node(uuid, workflow\_node\_create\_schema) Create Workflow Node Create a new node in a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_node_create_schema import WorkflowNodeCreateSchema from cyberwave.rest.models.workflow_node_schema import WorkflowNodeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workflow_node_create_schema = cyberwave.rest.WorkflowNodeCreateSchema() # WorkflowNodeCreateSchema | try: # Create Workflow Node api_response = api_instance.src_app_api_workflows_create_workflow_node(uuid, workflow_node_create_schema) print("The response of DefaultApi->src_app_api_workflows_create_workflow_node:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_create_workflow_node: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workflow\_node\_create\_schema** | [**WorkflowNodeCreateSchema**](/api-reference/rest/WorkflowNodeCreateSchema) | | | ### Return type [**WorkflowNodeSchema**](/api-reference/rest/WorkflowNodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_deactivate\_workflow** > WorkflowSchema src\_app\_api\_workflows\_deactivate\_workflow(uuid) Deactivate Workflow Deactivate a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_schema import WorkflowSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Deactivate Workflow api_response = api_instance.src_app_api_workflows_deactivate_workflow(uuid) print("The response of DefaultApi->src_app_api_workflows_deactivate_workflow:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_deactivate_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**WorkflowSchema**](/api-reference/rest/WorkflowSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_delete\_workflow** > src\_app\_api\_workflows\_delete\_workflow(uuid) Delete Workflow Delete a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Workflow api_instance.src_app_api_workflows_delete_workflow(uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_delete_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_delete\_workflow\_connection** > src\_app\_api\_workflows\_delete\_workflow\_connection(uuid, connection\_uuid) Delete Workflow Connection Delete a workflow connection. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | connection_uuid = 'connection_uuid_example' # str | try: # Delete Workflow Connection api_instance.src_app_api_workflows_delete_workflow_connection(uuid, connection_uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_delete_workflow_connection: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **connection\_uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_delete\_workflow\_node** > src\_app\_api\_workflows\_delete\_workflow\_node(uuid, node\_uuid) Delete Workflow Node Delete a workflow node. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | node_uuid = 'node_uuid_example' # str | try: # Delete Workflow Node api_instance.src_app_api_workflows_delete_workflow_node(uuid, node_uuid) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_delete_workflow_node: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **node\_uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_edge\_sync\_workflows** > Dict\[str, object] src\_app\_api\_workflows\_edge\_sync\_workflows(twin\_uuid) Edge Sync Workflows Sync workflows for an edge node. Returns active workflows with camera\_frame triggers for the specified twin, along with resolved plugin requirements from MLModel metadata. Edge nodes call this to know: 1. Which workflows to run 2. Which plugins/models to install 3. What events to emit ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) twin_uuid = 'twin_uuid_example' # str | try: # Edge Sync Workflows api_response = api_instance.src_app_api_workflows_edge_sync_workflows(twin_uuid) print("The response of DefaultApi->src_app_api_workflows_edge_sync_workflows:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_edge_sync_workflows: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_execute\_workflow** > WorkflowExecutionSchema src\_app\_api\_workflows\_execute\_workflow(uuid, workflow\_execute\_schema) Execute Workflow Manually trigger a workflow execution. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_execute_schema import WorkflowExecuteSchema from cyberwave.rest.models.workflow_execution_schema import WorkflowExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workflow_execute_schema = cyberwave.rest.WorkflowExecuteSchema() # WorkflowExecuteSchema | try: # Execute Workflow api_response = api_instance.src_app_api_workflows_execute_workflow(uuid, workflow_execute_schema) print("The response of DefaultApi->src_app_api_workflows_execute_workflow:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_execute_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ---------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workflow\_execute\_schema** | [**WorkflowExecuteSchema**](/api-reference/rest/WorkflowExecuteSchema) | | | ### Return type [**WorkflowExecutionSchema**](/api-reference/rest/WorkflowExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_get\_execution\_by\_uuid** > WorkflowExecutionSchema src\_app\_api\_workflows\_get\_execution\_by\_uuid(execution\_uuid) Get Execution By Uuid Get details of a specific execution by its UUID, including node executions. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_execution_schema import WorkflowExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) execution_uuid = 'execution_uuid_example' # str | try: # Get Execution By Uuid api_response = api_instance.src_app_api_workflows_get_execution_by_uuid(execution_uuid) print("The response of DefaultApi->src_app_api_workflows_get_execution_by_uuid:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_get_execution_by_uuid: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **execution\_uuid** | **str** | | | ### Return type [**WorkflowExecutionSchema**](/api-reference/rest/WorkflowExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_get\_node\_schema** > Dict\[str, object] src\_app\_api\_workflows\_get\_node\_schema(node\_type, node\_subtype=node\_subtype) Get Node Schema Get the schema for a specific node type. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) node_type = 'node_type_example' # str | node_subtype = 'node_subtype_example' # str | (optional) try: # Get Node Schema api_response = api_instance.src_app_api_workflows_get_node_schema(node_type, node_subtype=node_subtype) print("The response of DefaultApi->src_app_api_workflows_get_node_schema:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_get_node_schema: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----------- | | **node\_type** | **str** | | | | **node\_subtype** | **str** | | \[optional] | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_get\_node\_schemas** > List\[Dict\[str, object]] src\_app\_api\_workflows\_get\_node\_schemas() Get Node Schemas Get all available node type schemas with their input/output definitions. This is used by the frontend to display available node types and their I/O. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Node Schemas api_response = api_instance.src_app_api_workflows_get_node_schemas() print("The response of DefaultApi->src_app_api_workflows_get_node_schemas:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_get_node_schemas: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type **List\[Dict\[str, object]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_get\_workflow** > WorkflowSchema src\_app\_api\_workflows\_get\_workflow(uuid) Get Workflow Get a specific workflow with its nodes and connections. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_schema import WorkflowSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Workflow api_response = api_instance.src_app_api_workflows_get_workflow(uuid) print("The response of DefaultApi->src_app_api_workflows_get_workflow:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_get_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**WorkflowSchema**](/api-reference/rest/WorkflowSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_get\_workflow\_execution** > WorkflowExecutionSchema src\_app\_api\_workflows\_get\_workflow\_execution(uuid, execution\_uuid) Get Workflow Execution Get a specific execution for a workflow with full details including node executions. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_execution_schema import WorkflowExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | execution_uuid = 'execution_uuid_example' # str | try: # Get Workflow Execution api_response = api_instance.src_app_api_workflows_get_workflow_execution(uuid, execution_uuid) print("The response of DefaultApi->src_app_api_workflows_get_workflow_execution:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_get_workflow_execution: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **execution\_uuid** | **str** | | | ### Return type [**WorkflowExecutionSchema**](/api-reference/rest/WorkflowExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_get\_workflow\_node** > WorkflowNodeSchema src\_app\_api\_workflows\_get\_workflow\_node(uuid, node\_uuid) Get Workflow Node Get a specific node. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_node_schema import WorkflowNodeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | node_uuid = 'node_uuid_example' # str | try: # Get Workflow Node api_response = api_instance.src_app_api_workflows_get_workflow_node(uuid, node_uuid) print("The response of DefaultApi->src_app_api_workflows_get_workflow_node:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_get_workflow_node: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **node\_uuid** | **str** | | | ### Return type [**WorkflowNodeSchema**](/api-reference/rest/WorkflowNodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_list\_workflow\_connections** > List\[WorkflowConnectionSchema] src\_app\_api\_workflows\_list\_workflow\_connections(uuid) List Workflow Connections List all connections in a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_connection_schema import WorkflowConnectionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Workflow Connections api_response = api_instance.src_app_api_workflows_list_workflow_connections(uuid) print("The response of DefaultApi->src_app_api_workflows_list_workflow_connections:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_list_workflow_connections: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[WorkflowConnectionSchema\]**](/api-reference/rest/WorkflowConnectionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_list\_workflow\_executions** > List\[WorkflowExecutionSchema] src\_app\_api\_workflows\_list\_workflow\_executions(uuid) List Workflow Executions List all executions for a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_execution_schema import WorkflowExecutionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Workflow Executions api_response = api_instance.src_app_api_workflows_list_workflow_executions(uuid) print("The response of DefaultApi->src_app_api_workflows_list_workflow_executions:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_list_workflow_executions: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[WorkflowExecutionSchema\]**](/api-reference/rest/WorkflowExecutionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_list\_workflow\_nodes** > List\[WorkflowNodeSchema] src\_app\_api\_workflows\_list\_workflow\_nodes(uuid) List Workflow Nodes List all nodes in a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_node_schema import WorkflowNodeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Workflow Nodes api_response = api_instance.src_app_api_workflows_list_workflow_nodes(uuid) print("The response of DefaultApi->src_app_api_workflows_list_workflow_nodes:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_list_workflow_nodes: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**List\[WorkflowNodeSchema\]**](/api-reference/rest/WorkflowNodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_list\_workflows** > List\[WorkflowSchema] src\_app\_api\_workflows\_list\_workflows() List Workflows List all workflows for the authenticated user's workspace. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_schema import WorkflowSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Workflows api_response = api_instance.src_app_api_workflows_list_workflows() print("The response of DefaultApi->src_app_api_workflows_list_workflows:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_list_workflows: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[WorkflowSchema\]**](/api-reference/rest/WorkflowSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_update\_workflow** > WorkflowSchema src\_app\_api\_workflows\_update\_workflow(uuid, workflow\_update\_schema) Update Workflow Update a workflow. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_schema import WorkflowSchema from cyberwave.rest.models.workflow_update_schema import WorkflowUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workflow_update_schema = cyberwave.rest.WorkflowUpdateSchema() # WorkflowUpdateSchema | try: # Update Workflow api_response = api_instance.src_app_api_workflows_update_workflow(uuid, workflow_update_schema) print("The response of DefaultApi->src_app_api_workflows_update_workflow:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_update_workflow: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------- | -------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workflow\_update\_schema** | [**WorkflowUpdateSchema**](/api-reference/rest/WorkflowUpdateSchema) | | | ### Return type [**WorkflowSchema**](/api-reference/rest/WorkflowSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_update\_workflow\_node** > WorkflowNodeSchema src\_app\_api\_workflows\_update\_workflow\_node(uuid, node\_uuid, workflow\_node\_update\_schema) Update Workflow Node Update a workflow node. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workflow_node_schema import WorkflowNodeSchema from cyberwave.rest.models.workflow_node_update_schema import WorkflowNodeUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | node_uuid = 'node_uuid_example' # str | workflow_node_update_schema = cyberwave.rest.WorkflowNodeUpdateSchema() # WorkflowNodeUpdateSchema | try: # Update Workflow Node api_response = api_instance.src_app_api_workflows_update_workflow_node(uuid, node_uuid, workflow_node_update_schema) print("The response of DefaultApi->src_app_api_workflows_update_workflow_node:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_update_workflow_node: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **node\_uuid** | **str** | | | | **workflow\_node\_update\_schema** | [**WorkflowNodeUpdateSchema**](/api-reference/rest/WorkflowNodeUpdateSchema) | | | ### Return type [**WorkflowNodeSchema**](/api-reference/rest/WorkflowNodeSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_workflows\_validate\_node\_inputs** > Dict\[str, object] src\_app\_api\_workflows\_validate\_node\_inputs(node\_uuid) Validate Node Inputs Validate that a node's input mappings are complete and correct. Returns validation status and any error messages. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) node_uuid = 'node_uuid_example' # str | try: # Validate Node Inputs api_response = api_instance.src_app_api_workflows_validate_node_inputs(node_uuid) print("The response of DefaultApi->src_app_api_workflows_validate_node_inputs:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_app_api_workflows_validate_node_inputs: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **node\_uuid** | **str** | | | ### Return type **Dict\[str, object]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_add\_organization\_member\_by\_email** > AddMemberByEmailResponse src\_users\_api\_organizations\_add\_organization\_member\_by\_email(uuid, add\_member\_by\_email\_request) Add Organization Member By Email Add a member to an organization by email address. If user exists in Cyberwave, add them to the organization. If user doesn't exist, return user\_exists=False so frontend can show contact link. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.add_member_by_email_request import AddMemberByEmailRequest from cyberwave.rest.models.add_member_by_email_response import AddMemberByEmailResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | add_member_by_email_request = cyberwave.rest.AddMemberByEmailRequest() # AddMemberByEmailRequest | try: # Add Organization Member By Email api_response = api_instance.src_users_api_organizations_add_organization_member_by_email(uuid, add_member_by_email_request) print("The response of DefaultApi->src_users_api_organizations_add_organization_member_by_email:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_add_organization_member_by_email: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **add\_member\_by\_email\_request** | [**AddMemberByEmailRequest**](/api-reference/rest/AddMemberByEmailRequest) | | | ### Return type [**AddMemberByEmailResponse**](/api-reference/rest/AddMemberByEmailResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_create\_organization** > Dict\[str, OrganizationSchema] src\_users\_api\_organizations\_create\_organization(organization\_create\_schema) Create Organization Create a new organization ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.organization_create_schema import OrganizationCreateSchema from cyberwave.rest.models.organization_schema import OrganizationSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) organization_create_schema = cyberwave.rest.OrganizationCreateSchema() # OrganizationCreateSchema | try: # Create Organization api_response = api_instance.src_users_api_organizations_create_organization(organization_create_schema) print("The response of DefaultApi->src_users_api_organizations_create_organization:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_create_organization: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **organization\_create\_schema** | [**OrganizationCreateSchema**](/api-reference/rest/OrganizationCreateSchema) | | | ### Return type [**Dict\[str, OrganizationSchema\]**](/api-reference/rest/OrganizationSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_delete\_organization** > src\_users\_api\_organizations\_delete\_organization(uuid) Delete Organization Delete an organization ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Organization api_instance.src_users_api_organizations_delete_organization(uuid) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_delete_organization: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_get\_organization** > Dict\[str, OrganizationSchema] src\_users\_api\_organizations\_get\_organization(uuid) Get Organization Retrieve an organization ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.organization_schema import OrganizationSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Organization api_response = api_instance.src_users_api_organizations_get_organization(uuid) print("The response of DefaultApi->src_users_api_organizations_get_organization:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_get_organization: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**Dict\[str, OrganizationSchema\]**](/api-reference/rest/OrganizationSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_get\_organization\_by\_slug** > Dict\[str, OrganizationSchema] src\_users\_api\_organizations\_get\_organization\_by\_slug(slug) Get Organization By Slug ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.organization_schema import OrganizationSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) slug = 'slug_example' # str | try: # Get Organization By Slug api_response = api_instance.src_users_api_organizations_get_organization_by_slug(slug) print("The response of DefaultApi->src_users_api_organizations_get_organization_by_slug:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_get_organization_by_slug: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **slug** | **str** | | | ### Return type [**Dict\[str, OrganizationSchema\]**](/api-reference/rest/OrganizationSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_list\_organization\_members** > OrgMembersResponse src\_users\_api\_organizations\_list\_organization\_members(uuid) List Organization Members List all members of an organization ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.org_members_response import OrgMembersResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Organization Members api_response = api_instance.src_users_api_organizations_list_organization_members(uuid) print("The response of DefaultApi->src_users_api_organizations_list_organization_members:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_list_organization_members: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**OrgMembersResponse**](/api-reference/rest/OrgMembersResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_list\_organization\_workspaces** > Dict\[str, List\[OrganizationWorkspaceSchema]] src\_users\_api\_organizations\_list\_organization\_workspaces(uuid) List Organization Workspaces List all workspaces in an organization for authorized org users. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.organization_workspace_schema import OrganizationWorkspaceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # List Organization Workspaces api_response = api_instance.src_users_api_organizations_list_organization_workspaces(uuid) print("The response of DefaultApi->src_users_api_organizations_list_organization_workspaces:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_list_organization_workspaces: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type **Dict\[str, List\[OrganizationWorkspaceSchema]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_list\_organizations** > Dict\[str, List\[OrganizationSchema]] src\_users\_api\_organizations\_list\_organizations() List Organizations List all organizations ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.organization_schema import OrganizationSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Organizations api_response = api_instance.src_users_api_organizations_list_organizations() print("The response of DefaultApi->src_users_api_organizations_list_organizations:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_list_organizations: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type **Dict\[str, List\[OrganizationSchema]]** ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_remove\_organization\_member** > src\_users\_api\_organizations\_remove\_organization\_member(uuid, user\_uuid) Remove Organization Member Remove a member from an organization ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | user_uuid = 'user_uuid_example' # str | try: # Remove Organization Member api_instance.src_users_api_organizations_remove_organization_member(uuid, user_uuid) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_remove_organization_member: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **user\_uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_update\_organization** > Dict\[str, OrganizationSchema] src\_users\_api\_organizations\_update\_organization(uuid, organization\_update\_schema) Update Organization Update an organization ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.organization_schema import OrganizationSchema from cyberwave.rest.models.organization_update_schema import OrganizationUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | organization_update_schema = cyberwave.rest.OrganizationUpdateSchema() # OrganizationUpdateSchema | try: # Update Organization api_response = api_instance.src_users_api_organizations_update_organization(uuid, organization_update_schema) print("The response of DefaultApi->src_users_api_organizations_update_organization:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_update_organization: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **organization\_update\_schema** | [**OrganizationUpdateSchema**](/api-reference/rest/OrganizationUpdateSchema) | | | ### Return type [**Dict\[str, OrganizationSchema\]**](/api-reference/rest/OrganizationSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_organizations\_update\_organization\_member\_role** > UpdateMemberRoleResponse src\_users\_api\_organizations\_update\_organization\_member\_role(uuid, user\_uuid, update\_member\_role\_request) Update Organization Member Role Update the role of an organization member. Only organization owner or admin can update roles. Cannot change the role of the organization owner. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.update_member_role_request import UpdateMemberRoleRequest from cyberwave.rest.models.update_member_role_response import UpdateMemberRoleResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | user_uuid = 'user_uuid_example' # str | update_member_role_request = cyberwave.rest.UpdateMemberRoleRequest() # UpdateMemberRoleRequest | try: # Update Organization Member Role api_response = api_instance.src_users_api_organizations_update_organization_member_role(uuid, user_uuid, update_member_role_request) print("The response of DefaultApi->src_users_api_organizations_update_organization_member_role:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_organizations_update_organization_member_role: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **user\_uuid** | **str** | | | | **update\_member\_role\_request** | [**UpdateMemberRoleRequest**](/api-reference/rest/UpdateMemberRoleRequest) | | | ### Return type [**UpdateMemberRoleResponse**](/api-reference/rest/UpdateMemberRoleResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_plans\_get\_plan** > PlanSchema src\_users\_api\_plans\_get\_plan() Get Plan Get the plan for the current user ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.plan_schema import PlanSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Plan api_response = api_instance.src_users_api_plans_get_plan() print("The response of DefaultApi->src_users_api_plans_get_plan:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_plans_get_plan: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**PlanSchema**](/api-reference/rest/PlanSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_add\_workspace\_member\_by\_email** > AddMemberByEmailResponse src\_users\_api\_workspaces\_add\_workspace\_member\_by\_email(uuid, add\_member\_by\_email\_request) Add Workspace Member By Email Add a member to a workspace by email address. If user exists in Cyberwave, add them to the workspace. If user doesn't exist, return user\_exists=False so frontend can show contact link. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.add_member_by_email_request import AddMemberByEmailRequest from cyberwave.rest.models.add_member_by_email_response import AddMemberByEmailResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | add_member_by_email_request = cyberwave.rest.AddMemberByEmailRequest() # AddMemberByEmailRequest | try: # Add Workspace Member By Email api_response = api_instance.src_users_api_workspaces_add_workspace_member_by_email(uuid, add_member_by_email_request) print("The response of DefaultApi->src_users_api_workspaces_add_workspace_member_by_email:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_add_workspace_member_by_email: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **add\_member\_by\_email\_request** | [**AddMemberByEmailRequest**](/api-reference/rest/AddMemberByEmailRequest) | | | ### Return type [**AddMemberByEmailResponse**](/api-reference/rest/AddMemberByEmailResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_check\_workspace\_slug** > SlugAvailabilitySchema src\_users\_api\_workspaces\_check\_workspace\_slug(slug) Check Workspace Slug Check if a workspace slug is available ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.slug_availability_schema import SlugAvailabilitySchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) slug = 'slug_example' # str | try: # Check Workspace Slug api_response = api_instance.src_users_api_workspaces_check_workspace_slug(slug) print("The response of DefaultApi->src_users_api_workspaces_check_workspace_slug:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_check_workspace_slug: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **slug** | **str** | | | ### Return type [**SlugAvailabilitySchema**](/api-reference/rest/SlugAvailabilitySchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_create\_workspace** > WorkspaceSchema src\_users\_api\_workspaces\_create\_workspace(workspace\_create\_schema=workspace\_create\_schema) Create Workspace Create a workspace ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workspace_create_schema import WorkspaceCreateSchema from cyberwave.rest.models.workspace_schema import WorkspaceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) workspace_create_schema = cyberwave.rest.WorkspaceCreateSchema() # WorkspaceCreateSchema | (optional) try: # Create Workspace api_response = api_instance.src_users_api_workspaces_create_workspace(workspace_create_schema=workspace_create_schema) print("The response of DefaultApi->src_users_api_workspaces_create_workspace:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_create_workspace: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ---------------------------------------------------------------------- | ----------- | ----------- | | **workspace\_create\_schema** | [**WorkspaceCreateSchema**](/api-reference/rest/WorkspaceCreateSchema) | | \[optional] | ### Return type [**WorkspaceSchema**](/api-reference/rest/WorkspaceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_delete\_workspace** > src\_users\_api\_workspaces\_delete\_workspace(uuid) Delete Workspace Delete a workspace ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Delete Workspace api_instance.src_users_api_workspaces_delete_workspace(uuid) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_delete_workspace: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_get\_default\_workspace** > WorkspaceSchema src\_users\_api\_workspaces\_get\_default\_workspace() Get Default Workspace Get the user's default workspace ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workspace_schema import WorkspaceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # Get Default Workspace api_response = api_instance.src_users_api_workspaces_get_default_workspace() print("The response of DefaultApi->src_users_api_workspaces_get_default_workspace:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_get_default_workspace: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**WorkspaceSchema**](/api-reference/rest/WorkspaceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_get\_vendor\_description** > VendorDescriptionSchema src\_users\_api\_workspaces\_get\_vendor\_description(slug) Get Vendor Description Get vendor description by slug (no authentication required) ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.vendor_description_schema import VendorDescriptionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) slug = 'slug_example' # str | try: # Get Vendor Description api_response = api_instance.src_users_api_workspaces_get_vendor_description(slug) print("The response of DefaultApi->src_users_api_workspaces_get_vendor_description:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_get_vendor_description: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **slug** | **str** | | | ### Return type [**VendorDescriptionSchema**](/api-reference/rest/VendorDescriptionSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_get\_workspace** > WorkspaceResponseSchema src\_users\_api\_workspaces\_get\_workspace(uuid) Get Workspace Retrieve a workspace ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workspace_response_schema import WorkspaceResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | try: # Get Workspace api_response = api_instance.src_users_api_workspaces_get_workspace(uuid) print("The response of DefaultApi->src_users_api_workspaces_get_workspace:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_get_workspace: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | ### Return type [**WorkspaceResponseSchema**](/api-reference/rest/WorkspaceResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_get\_workspace\_by\_slug** > WorkspaceSchema src\_users\_api\_workspaces\_get\_workspace\_by\_slug(slug) Get Workspace By Slug Retrieve a workspace by slug (public endpoint) ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workspace_schema import WorkspaceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) slug = 'slug_example' # str | try: # Get Workspace By Slug api_response = api_instance.src_users_api_workspaces_get_workspace_by_slug(slug) print("The response of DefaultApi->src_users_api_workspaces_get_workspace_by_slug:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_get_workspace_by_slug: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **slug** | **str** | | | ### Return type [**WorkspaceSchema**](/api-reference/rest/WorkspaceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_leave\_team** > src\_users\_api\_workspaces\_leave\_team(team\_uuid, uuid) Leave Team Leave a team ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) team_uuid = 'team_uuid_example' # str | uuid = 'uuid_example' # str | try: # Leave Team api_instance.src_users_api_workspaces_leave_team(team_uuid, uuid) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_leave_team: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **team\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_list\_team\_members** > List\[TeamMemberResponse] src\_users\_api\_workspaces\_list\_team\_members(team\_uuid) List Team Members Get the members of a team ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.team_member_response import TeamMemberResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) team_uuid = 'team_uuid_example' # str | try: # List Team Members api_response = api_instance.src_users_api_workspaces_list_team_members(team_uuid) print("The response of DefaultApi->src_users_api_workspaces_list_team_members:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_list_team_members: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **team\_uuid** | **str** | | | ### Return type [**List\[TeamMemberResponse\]**](/api-reference/rest/TeamMemberResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_list\_workspaces** > List\[WorkspaceSchema] src\_users\_api\_workspaces\_list\_workspaces() List Workspaces List all workspaces ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workspace_schema import WorkspaceSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) try: # List Workspaces api_response = api_instance.src_users_api_workspaces_list_workspaces() print("The response of DefaultApi->src_users_api_workspaces_list_workspaces:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_list_workspaces: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**List\[WorkspaceSchema\]**](/api-reference/rest/WorkspaceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_remove\_team\_member** > src\_users\_api\_workspaces\_remove\_team\_member(team\_uuid, uuid) Remove Team Member Delete a member from a team ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) team_uuid = 'team_uuid_example' # str | uuid = 'uuid_example' # str | try: # Remove Team Member api_instance.src_users_api_workspaces_remove_team_member(team_uuid, uuid) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_remove_team_member: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **team\_uuid** | **str** | | | | **uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_remove\_workspace\_member** > RemoveMemberResponse src\_users\_api\_workspaces\_remove\_workspace\_member(uuid, user\_uuid) Remove Workspace Member Remove a member from a workspace. Only workspace owner or organization owner can remove members. Cannot remove the workspace owner or the last member. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.remove_member_response import RemoveMemberResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | user_uuid = 'user_uuid_example' # str | try: # Remove Workspace Member api_response = api_instance.src_users_api_workspaces_remove_workspace_member(uuid, user_uuid) print("The response of DefaultApi->src_users_api_workspaces_remove_workspace_member:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_remove_workspace_member: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **user\_uuid** | **str** | | | ### Return type [**RemoveMemberResponse**](/api-reference/rest/RemoveMemberResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_set\_default\_workspace** > src\_users\_api\_workspaces\_set\_default\_workspace(workspace\_uuid) Set Default Workspace Set the user's default workspace ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) workspace_uuid = 'workspace_uuid_example' # str | try: # Set Default Workspace api_instance.src_users_api_workspaces_set_default_workspace(workspace_uuid) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_set_default_workspace: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----- | | **workspace\_uuid** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_update\_workspace** > WorkspaceSchema src\_users\_api\_workspaces\_update\_workspace(uuid, workspace\_update\_schema) Update Workspace Update a workspace ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.workspace_schema import WorkspaceSchema from cyberwave.rest.models.workspace_update_schema import WorkspaceUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | workspace_update_schema = cyberwave.rest.WorkspaceUpdateSchema() # WorkspaceUpdateSchema | try: # Update Workspace api_response = api_instance.src_users_api_workspaces_update_workspace(uuid, workspace_update_schema) print("The response of DefaultApi->src_users_api_workspaces_update_workspace:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_update_workspace: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------------------------- | ---------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workspace\_update\_schema** | [**WorkspaceUpdateSchema**](/api-reference/rest/WorkspaceUpdateSchema) | | | ### Return type [**WorkspaceSchema**](/api-reference/rest/WorkspaceSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_workspaces\_update\_workspace\_member\_role** > UpdateMemberRoleResponse src\_users\_api\_workspaces\_update\_workspace\_member\_role(uuid, user\_uuid, update\_member\_role\_request) Update Workspace Member Role Update the role of a workspace member. Only workspace owner or organization owner/admin can update roles. Cannot change the role of the workspace owner. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.update_member_role_request import UpdateMemberRoleRequest from cyberwave.rest.models.update_member_role_response import UpdateMemberRoleResponse from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.DefaultApi(api_client) uuid = 'uuid_example' # str | user_uuid = 'user_uuid_example' # str | update_member_role_request = cyberwave.rest.UpdateMemberRoleRequest() # UpdateMemberRoleRequest | try: # Update Workspace Member Role api_response = api_instance.src_users_api_workspaces_update_workspace_member_role(uuid, user_uuid, update_member_role_request) print("The response of DefaultApi->src_users_api_workspaces_update_workspace_member_role:\n") pprint(api_response) except Exception as e: print("Exception when calling DefaultApi->src_users_api_workspaces_update_workspace_member_role: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **user\_uuid** | **str** | | | | **update\_member\_role\_request** | [**UpdateMemberRoleRequest**](/api-reference/rest/UpdateMemberRoleRequest) | | | ### Return type [**UpdateMemberRoleResponse**](/api-reference/rest/UpdateMemberRoleResponse) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # DeferredTaskExecutionResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/DeferredTaskExecutionResponseSchema # DeferredTaskExecutionResponseSchema Schema for a Deferred Execution. ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----- | | **execution\_uuid** | **str** | | | | **status** | **str** | | | | **result** | **Dict\[str, object]** | | | | **started\_at** | **datetime** | | | | **completed\_at** | **datetime** | | | | **message** | **str** | | | | **workload\_uuid** | **str** | | | # DiscoveryResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/DiscoveryResponseSchema # DiscoveryResponseSchema Schema for discovery API response. ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------------------------------------------------------- | ----------- | ----- | | **edge\_uuid** | **str** | | | | **fingerprint** | **str** | | | | **twins** | [**List\[TwinBindingSchema\]**](/api-reference/rest/TwinBindingSchema) | | | # EdgeCoreRestartResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/EdgeCoreRestartResponseSchema # EdgeCoreRestartResponseSchema Schema for requesting an edge-core restart. ## Properties | Name | Type | Description | Notes | | --------------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **edge\_uuid** | **str** | | | | **request\_id** | **str** | | | | **command** | **str** | | | | **topic** | **str** | | | # EdgeCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/EdgeCreateSchema # EdgeCreateSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **fingerprint** | **str** | | | | **name** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # EdgeRegisterSchema Source: https://docs.cyberwave.com/api-reference/rest/EdgeRegisterSchema # EdgeRegisterSchema Schema for registering an edge. ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ---------------------------- | | **fingerprint** | **str** | | | | **hostname** | **str** | | \[optional] \[default to ''] | | **platform** | **str** | | \[optional] \[default to ''] | | **name** | **str** | | \[optional] \[default to ''] | # EdgeSchema Source: https://docs.cyberwave.com/api-reference/rest/EdgeSchema # EdgeSchema Edge device schema using resolver mixins. ## Properties | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **organization\_uuid** | **str** | | | | **metadata** | **Dict\[str, object]** | | | # EnableOrgFeatureRequest Source: https://docs.cyberwave.com/api-reference/rest/EnableOrgFeatureRequest # EnableOrgFeatureRequest ## Properties | Name | Type | Description | Notes | | ---------------------- | ------------ | ----------- | ----------- | | **organization\_uuid** | **str** | | \[optional] | | **feature** | **str** | | | | **expires\_at** | **datetime** | | \[optional] | # EndSessionResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/EndSessionResponseSchema # EndSessionResponseSchema ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | # EnvironmentCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentCreateSchema # EnvironmentCreateSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | | | **description** | **str** | | | | **settings** | **Dict\[str, object]** | | \[optional] | | **asset\_uuid** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | \[optional] | | **project\_uuid** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] | # EnvironmentSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentSchema # EnvironmentSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **project\_uuid** | **str** | | | | **workspace\_uuid** | **str** | | \[optional] | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **settings** | **Dict\[str, object]** | | \[optional] | | **visibility** | **str** | | \[optional] | # EnvironmentSnapshotCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentSnapshotCreateSchema # EnvironmentSnapshotCreateSchema Schema for creating an environment snapshot. ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ----- | | **name** | **str** | | | | **description** | **str** | | | # EnvironmentSnapshotSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentSnapshotSchema # EnvironmentSnapshotSchema Schema for environment snapshot. ## Properties | Name | Type | Description | Notes | | ----------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | | | **updated\_by** | **str** | | | | **environment** | **str** | | | | **snapshot** | **Dict\[str, object]** | | | | **snapshot\_hash\_key** | **str** | | | # EnvironmentWaypointBulkCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentWaypointBulkCreateSchema # EnvironmentWaypointBulkCreateSchema stub Use `POST /api/v1/environments/{uuid}/waypoints` to append multiple waypoints to an environment in one request. ## Body | Name | Type | Description | Notes | | ------------- | -------------------------------------- | -------------------- | -------- | | **waypoints** | **EnvironmentWaypointCreateSchema\[]** | Waypoints to append. | required | # EnvironmentWaypointCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentWaypointCreateSchema # EnvironmentWaypointCreateSchema stub Waypoint payload accepted by `POST /api/v1/environments/{uuid}/waypoints`. ## Properties | Name | Type | Description | Notes | | -------------- | ---------------------- | ------------------------------------------------ | ----------- | | **id** | **str** | Optional waypoint identifier. | \[optional] | | **name** | **str** | Optional display name. | \[optional] | | **collection** | **str** | Optional grouping label. | \[optional] | | **position** | **Vector3Schema** | Position with `x`, `y`, and `z`. | \[optional] | | **rotation** | **QuaternionSchema** | Quaternion rotation with `w`, `x`, `y`, and `z`. | \[optional] | | **metadata** | **Dict\[str, object]** | Optional waypoint metadata. | \[optional] | # EnvironmentWaypointSchema Source: https://docs.cyberwave.com/api-reference/rest/EnvironmentWaypointSchema # EnvironmentWaypointSchema stub Normalized environment waypoint returned by the REST API. ## Properties | Name | Type | Description | Notes | | -------------- | ---------------------- | ------------------------------------------------ | ----------- | | **id** | **str** | Waypoint identifier. | | | **name** | **str** | Display name. | | | **collection** | **str** | Optional grouping label. | \[optional] | | **position** | **Vector3Schema** | Position with `x`, `y`, and `z`. | | | **rotation** | **QuaternionSchema** | Quaternion rotation with `w`, `x`, `y`, and `z`. | | | **metadata** | **Dict\[str, object]** | Optional waypoint metadata. | \[optional] | # EpisodeCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/EpisodeCreateSchema # EpisodeCreateSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ---------------------- | ----------- | ----------- | | **task\_name** | **str** | | | | **twins** | **List\[str]** | | | | **started\_at** | **int** | | | | **finished\_at** | **int** | | | | **metadata** | **Dict\[str, object]** | | \[optional] | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | # EpisodeSchema Source: https://docs.cyberwave.com/api-reference/rest/EpisodeSchema # EpisodeSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | **uuid** | **str** | | | | **task\_name** | **str** | | | | **twins** | **List\[str]** | | | | **started\_at** | **int** | | | | **finished\_at** | **int** | | | | **metadata** | **Dict\[str, object]** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | | **audio** | **List\[Dict\[str, object]]** | Trimmed MP3 audio companions for this episode, each with a signed playback URL (twin\_uuid, sensor\_id, format, first/last\_timestamp\_us, duration\_s, signed\_url). | \[optional] | # EpisodeUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/EpisodeUpdateSchema # EpisodeUpdateSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ---------------------- | ----------- | ----------- | | **task\_name** | **str** | | \[optional] | | **twins** | **List\[str]** | | \[optional] | | **started\_at** | **int** | | \[optional] | | **finished\_at** | **int** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | # ExecuteTaskSchema Source: https://docs.cyberwave.com/api-reference/rest/ExecuteTaskSchema # ExecuteTaskSchema Schema for executing a task on a twin. ## Properties | Name | Type | Description | Notes | | -------------- | ---------------------- | ----------- | ----------- | | **twin\_uuid** | **str** | | | | **parameters** | **Dict\[str, object]** | | \[optional] | # FeatureMetadataSchema Source: https://docs.cyberwave.com/api-reference/rest/FeatureMetadataSchema # FeatureMetadataSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ----- | | **code** | **str** | | | | **label** | **str** | | | | **description** | **str** | | | # FeatureStatusSchema Source: https://docs.cyberwave.com/api-reference/rest/FeatureStatusSchema # FeatureStatusSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------------ | ----------- | ----------- | | **feature** | **str** | | | | **label** | **str** | | | | **enabled** | **bool** | | | | **source** | **str** | | | | **reason** | **str** | | | | **expires\_at** | **datetime** | | \[optional] | # FeaturesApi Source: https://docs.cyberwave.com/api-reference/rest/FeaturesApi # cyberwave.rest.FeaturesApi All URIs are relative to *[http://localhost](http://localhost)* | Method | HTTP request | Description | | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ---------------------- | | [**src\_app\_api\_features\_delete\_user\_feature**](#src_app_api_features_delete_user_feature) | **DELETE** `/api/v1/features/admin/users/{user_uuid}/{feature}` | Delete User Feature | | [**src\_app\_api\_features\_disable\_org\_feature**](#src_app_api_features_disable_org_feature) | **POST** /api/v1/features/admin/organizations/disable | Disable Org Feature | | [**src\_app\_api\_features\_enable\_org\_feature**](#src_app_api_features_enable_org_feature) | **POST** /api/v1/features/admin/organizations/enable | Enable Org Feature | | [**src\_app\_api\_features\_get\_available\_features**](#src_app_api_features_get_available_features) | **GET** /api/v1/features/available | Get Available Features | | [**src\_app\_api\_features\_get\_my\_features**](#src_app_api_features_get_my_features) | **GET** /api/v1/features/my-features | Get My Features | | [**src\_app\_api\_features\_grant\_user\_feature**](#src_app_api_features_grant_user_feature) | **POST** /api/v1/features/admin/users/grant | Grant User Feature | | [**src\_app\_api\_features\_list\_org\_features**](#src_app_api_features_list_org_features) | **GET** /api/v1/features/admin/organizations | List Org Features | | [**src\_app\_api\_features\_list\_user\_features**](#src_app_api_features_list_user_features) | **GET** /api/v1/features/admin/users | List User Features | | [**src\_app\_api\_features\_revoke\_user\_feature**](#src_app_api_features_revoke_user_feature) | **POST** /api/v1/features/admin/users/revoke | Revoke User Feature | | [**src\_app\_api\_features\_search\_users**](#src_app_api_features_search_users) | **GET** /api/v1/features/admin/users/search | Search Users | # **src\_app\_api\_features\_delete\_user\_feature** > src\_app\_api\_features\_delete\_user\_feature(user\_uuid, feature) Delete User Feature Delete a user's feature flag entirely (user falls back to org-level access). Staff only. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) user_uuid = 'user_uuid_example' # str | feature = 'feature_example' # str | try: # Delete User Feature api_instance.src_app_api_features_delete_user_feature(user_uuid, feature) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_delete_user_feature: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **user\_uuid** | **str** | | | | **feature** | **str** | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_disable\_org\_feature** > src\_app\_api\_features\_disable\_org\_feature(enable\_org\_feature\_request) Disable Org Feature Disable a feature for an organization. Staff can disable for any org, org owners/admins can disable for their own org. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.enable_org_feature_request import EnableOrgFeatureRequest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) enable_org_feature_request = cyberwave.rest.EnableOrgFeatureRequest() # EnableOrgFeatureRequest | try: # Disable Org Feature api_instance.src_app_api_features_disable_org_feature(enable_org_feature_request) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_disable_org_feature: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **enable\_org\_feature\_request** | [**EnableOrgFeatureRequest**](/api-reference/rest/EnableOrgFeatureRequest) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_enable\_org\_feature** > OrgFeatureSchema src\_app\_api\_features\_enable\_org\_feature(enable\_org\_feature\_request) Enable Org Feature Enable a feature for an organization. Staff can enable for any org, org owners/admins can enable for their own org. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.enable_org_feature_request import EnableOrgFeatureRequest from cyberwave.rest.models.org_feature_schema import OrgFeatureSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) enable_org_feature_request = cyberwave.rest.EnableOrgFeatureRequest() # EnableOrgFeatureRequest | try: # Enable Org Feature api_response = api_instance.src_app_api_features_enable_org_feature(enable_org_feature_request) print("The response of FeaturesApi->src_app_api_features_enable_org_feature:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_enable_org_feature: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **enable\_org\_feature\_request** | [**EnableOrgFeatureRequest**](/api-reference/rest/EnableOrgFeatureRequest) | | | ### Return type [**OrgFeatureSchema**](/api-reference/rest/OrgFeatureSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_get\_available\_features** > AvailableFeaturesSchema src\_app\_api\_features\_get\_available\_features() Get Available Features Get list of all available features with metadata. ### Example ```python theme={null} import cyberwave.rest from cyberwave.rest.models.available_features_schema import AvailableFeaturesSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) try: # Get Available Features api_response = api_instance.src_app_api_features_get_available_features() print("The response of FeaturesApi->src_app_api_features_get_available_features:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_get_available_features: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**AvailableFeaturesSchema**](/api-reference/rest/AvailableFeaturesSchema) ### Authorization No authorization required ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_get\_my\_features** > MyFeaturesResponseSchema src\_app\_api\_features\_get\_my\_features() Get My Features Get all features and their status for the current user. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.my_features_response_schema import MyFeaturesResponseSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) try: # Get My Features api_response = api_instance.src_app_api_features_get_my_features() print("The response of FeaturesApi->src_app_api_features_get_my_features:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_get_my_features: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**MyFeaturesResponseSchema**](/api-reference/rest/MyFeaturesResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_grant\_user\_feature** > UserFeatureSchema src\_app\_api\_features\_grant\_user\_feature(grant\_user\_feature\_request) Grant User Feature Grant a feature to a specific user. Staff only. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.grant_user_feature_request import GrantUserFeatureRequest from cyberwave.rest.models.user_feature_schema import UserFeatureSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) grant_user_feature_request = cyberwave.rest.GrantUserFeatureRequest() # GrantUserFeatureRequest | try: # Grant User Feature api_response = api_instance.src_app_api_features_grant_user_feature(grant_user_feature_request) print("The response of FeaturesApi->src_app_api_features_grant_user_feature:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_grant_user_feature: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **grant\_user\_feature\_request** | [**GrantUserFeatureRequest**](/api-reference/rest/GrantUserFeatureRequest) | | | ### Return type [**UserFeatureSchema**](/api-reference/rest/UserFeatureSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_list\_org\_features** > List\[OrgFeatureSchema] src\_app\_api\_features\_list\_org\_features(feature=feature) List Org Features List all organization-level feature flags. Staff only. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.org_feature_schema import OrgFeatureSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) feature = 'feature_example' # str | (optional) try: # List Org Features api_response = api_instance.src_app_api_features_list_org_features(feature=feature) print("The response of FeaturesApi->src_app_api_features_list_org_features:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_list_org_features: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------- | ------- | ----------- | ----------- | | **feature** | **str** | | \[optional] | ### Return type [**List\[OrgFeatureSchema\]**](/api-reference/rest/OrgFeatureSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_list\_user\_features** > List\[UserFeatureSchema] src\_app\_api\_features\_list\_user\_features(feature=feature) List User Features List all user-level feature flags. Staff only. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.user_feature_schema import UserFeatureSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) feature = 'feature_example' # str | (optional) try: # List User Features api_response = api_instance.src_app_api_features_list_user_features(feature=feature) print("The response of FeaturesApi->src_app_api_features_list_user_features:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_list_user_features: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----------- | ------- | ----------- | ----------- | | **feature** | **str** | | \[optional] | ### Return type [**List\[UserFeatureSchema\]**](/api-reference/rest/UserFeatureSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_revoke\_user\_feature** > src\_app\_api\_features\_revoke\_user\_feature(revoke\_user\_feature\_request) Revoke User Feature Revoke a feature from a specific user. Staff only. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.revoke_user_feature_request import RevokeUserFeatureRequest from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) revoke_user_feature_request = cyberwave.rest.RevokeUserFeatureRequest() # RevokeUserFeatureRequest | try: # Revoke User Feature api_instance.src_app_api_features_revoke_user_feature(revoke_user_feature_request) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_revoke_user_feature: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **revoke\_user\_feature\_request** | [**RevokeUserFeatureRequest**](/api-reference/rest/RevokeUserFeatureRequest) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_app\_api\_features\_search\_users** > List\[UserSearchResultSchema] src\_app\_api\_features\_search\_users(q) Search Users Search users by email or name for granting features. Staff only. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.user_search_result_schema import UserSearchResultSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.FeaturesApi(api_client) q = 'q_example' # str | try: # Search Users api_response = api_instance.src_app_api_features_search_users(q) print("The response of FeaturesApi->src_app_api_features_search_users:\n") pprint(api_response) except Exception as e: print("Exception when calling FeaturesApi->src_app_api_features_search_users: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ----- | ------- | ----------- | ----- | | **q** | **str** | | | ### Return type [**List\[UserSearchResultSchema\]**](/api-reference/rest/UserSearchResultSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # GrantUserFeatureRequest Source: https://docs.cyberwave.com/api-reference/rest/GrantUserFeatureRequest # GrantUserFeatureRequest ## Properties | Name | Type | Description | Notes | | --------------- | ------------ | ----------- | ---------------------------- | | **user\_uuid** | **str** | | | | **feature** | **str** | | | | **reason** | **str** | | \[optional] \[default to ''] | | **expires\_at** | **datetime** | | \[optional] | # ImageBytes Source: https://docs.cyberwave.com/api-reference/rest/ImageBytes # ImageBytes ## Properties | Name | Type | Description | Notes | | ---- | ---- | ----------- | ----- | # ImageBytes1 Source: https://docs.cyberwave.com/api-reference/rest/ImageBytes1 # ImageBytes1 ## Properties | Name | Type | Description | Notes | | ---- | ---- | ----------- | ----- | # ImportResultSchema Source: https://docs.cyberwave.com/api-reference/rest/ImportResultSchema # ImportResultSchema ## Properties | Name | Type | Description | Notes | | ------------------------ | -------------- | ----------- | ----- | | **created\_count** | **int** | | | | **skipped\_count** | **int** | | | | **created\_twin\_uuids** | **List\[str]** | | | | **skipped\_reasons** | **List\[str]** | | | # InitiateLargeUploadResponse Source: https://docs.cyberwave.com/api-reference/rest/InitiateLargeUploadResponse # InitiateLargeUploadResponse ## Properties | Name | Type | Description | Notes | | --------------------- | --------- | ----------- | ----- | | **upload\_url** | **str** | | | | **storage\_key** | **str** | | | | **expires\_at\_unix** | **float** | | | # InitiateLargeUploadSchema Source: https://docs.cyberwave.com/api-reference/rest/InitiateLargeUploadSchema # InitiateLargeUploadSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----------- | | **filename** | **str** | | | | **content\_type** | **str** | | \[optional] | | **file\_size** | **int** | | \[optional] | # JointCalibrationSchema Source: https://docs.cyberwave.com/api-reference/rest/JointCalibrationSchema # JointCalibrationSchema Schema for a single joint's calibration (request/response). ## Properties | Name | Type | Description | Notes | | ------------------ | --------- | ----------- | ----------- | | **range\_min** | **float** | | | | **range\_max** | **float** | | | | **homing\_offset** | **float** | | | | **drive\_mode** | **str** | | | | **id** | **str** | | | | **lower** | **float** | | \[optional] | | **upper** | **float** | | \[optional] | # JointSchema Source: https://docs.cyberwave.com/api-reference/rest/JointSchema # JointSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ---------------------------- | ----------- | ----- | | **name** | **str** | | | | **type** | **str** | | | | **parent\_link** | **str** | | | | **child\_link** | **str** | | | | **axis** | **List\[float]** | | | | **limits** | **Dict\[str, float]** | | | | **origin** | **Dict\[str, List\[float]]** | | | # JointStateSchema Source: https://docs.cyberwave.com/api-reference/rest/JointStateSchema # JointStateSchema ## Properties | Name | Type | Description | Notes | | ------------ | --------- | ----------- | ----- | | **name** | **str** | | | | **position** | **float** | | | | **velocity** | **float** | | | | **effort** | **float** | | | # JointStateUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/JointStateUpdateSchema # JointStateUpdateSchema ## Properties | Name | Type | Description | Notes | | ------------ | --------- | ----------- | ----------- | | **position** | **float** | | \[optional] | | **velocity** | **float** | | \[optional] | | **effort** | **float** | | \[optional] | # JointStatesSchema Source: https://docs.cyberwave.com/api-reference/rest/JointStatesSchema # JointStatesSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------------------- | ----------- | ----- | | **header** | **Dict\[str, str]** | | | | **name** | **List\[str]** | | | | **position** | **List\[float]** | | | | **velocity** | **List\[float]** | | | | **effort** | **List\[float]** | | | # KeybindingCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/KeybindingCreateSchema # KeybindingCreateSchema Schema for creating a Keybinding. ## Properties | Name | Type | Description | Notes | | ---------------------- | ---------------------------------------- | ----------- | ----------- | | **name** | **str** | | | | **metadata** | **Dict\[str, object]** | | \[optional] | | **keyboard\_bindings** | **List\[Optional\[Dict\[str, object]]]** | | \[optional] | # KeybindingSchema Source: https://docs.cyberwave.com/api-reference/rest/KeybindingSchema # KeybindingSchema Schema for Keybinding model. ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **user\_uuid** | **str** | | \[optional] | # KeybindingUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/KeybindingUpdateSchema # KeybindingUpdateSchema Schema for updating a Keybinding. ## Properties | Name | Type | Description | Notes | | ---------------------- | ----------------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **keyboard\_bindings** | **List\[Dict\[str, object]]** | | \[optional] | # LLMGenerationSchema Source: https://docs.cyberwave.com/api-reference/rest/LLMGenerationSchema # LLMGenerationSchema ## Properties | Name | Type | Description | Notes | | ---------- | ------- | ----------- | ----- | | **prompt** | **str** | | | # LLMResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/LLMResponseSchema # LLMResponseSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **response** | **str** | | | # LabAccessResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/LabAccessResponseSchema # LabAccessResponseSchema ## Properties | Name | Type | Description | Notes | | ---------------------------- | -------- | ----------- | ------------------------------- | | **success** | **bool** | | | | **session\_status** | **str** | | | | **environment\_uuid** | **str** | | | | **environment\_name** | **str** | | | | **role** | **str** | | | | **message** | **str** | | | | **already\_had\_session** | **bool** | | \[optional] \[default to False] | | **queue\_position** | **int** | | \[optional] | | **estimated\_wait\_minutes** | **int** | | \[optional] | | **session\_expires\_at** | **str** | | \[optional] | # LabStatusResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/LabStatusResponseSchema # LabStatusResponseSchema ## Properties | Name | Type | Description | Notes | | ---------------------------- | -------- | ----------- | ---------------------------- | | **has\_session** | **bool** | | | | **lab\_status** | **str** | | | | **available** | **bool** | | | | **queue\_length** | **int** | | | | **queue\_position** | **int** | | \[optional] | | **estimated\_wait\_minutes** | **int** | | \[optional] | | **session\_status** | **str** | | \[optional] | | **session\_expires\_at** | **str** | | \[optional] | | **time\_remaining\_seconds** | **int** | | \[optional] | | **environment\_name** | **str** | | | | **environment\_uuid** | **str** | | \[optional] | | **message** | **str** | | \[optional] \[default to ''] | # LinkShareCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/LinkShareCreateSchema # LinkShareCreateSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ---------------------------------- | | **role\_cap** | **str** | | \[optional] \[default to 'reader'] | | **expires\_at** | **str** | | \[optional] | # LinkShareRevokeSchema Source: https://docs.cyberwave.com/api-reference/rest/LinkShareRevokeSchema # LinkShareRevokeSchema ## Properties | Name | Type | Description | Notes | | --------- | ------- | ----------- | ----- | | **token** | **str** | | | # LinkShareSchema Source: https://docs.cyberwave.com/api-reference/rest/LinkShareSchema # LinkShareSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------------ | ----------- | ----------- | | **token** | **str** | | | | **role\_cap** | **str** | | | | **expires\_at** | **datetime** | | \[optional] | | **created\_by** | **str** | | \[optional] | | **created\_at** | **datetime** | | | | **is\_active** | **bool** | | | # MLModelCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/MLModelCreateSchema # MLModelCreateSchema ## Properties | Name | Type | Description | Notes | | -------------------------------- | ---------------------- | ----------- | ----------------------------------- | | **name** | **str** | | | | **description** | **str** | | | | **workspace\_uuid** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **visibility** | **str** | | \[optional] \[default to 'private'] | | **tags** | **List\[str]** | | \[optional] | | **model\_external\_id** | **str** | | | | **model\_provider\_name** | **str** | | | | **mapped\_model\_id** | **str** | | \[optional] | | **output\_format** | **str** | | \[optional] | | **deployment** | **str** | | \[optional] \[default to 'cloud'] | | **can\_take\_video\_as\_input** | **bool** | | \[optional] \[default to False] | | **can\_take\_audio\_as\_input** | **bool** | | \[optional] \[default to False] | | **can\_take\_image\_as\_input** | **bool** | | \[optional] \[default to False] | | **can\_take\_text\_as\_input** | **bool** | | \[optional] \[default to True] | | **can\_take\_action\_as\_input** | **bool** | | \[optional] \[default to False] | # MLModelSchema Source: https://docs.cyberwave.com/api-reference/rest/MLModelSchema # MLModelSchema ML Model schema. ## Properties | Name | Type | Description | Notes | | -------------------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | | **workspace\_uuid** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **visibility** | **str** | | | | **tags** | **List\[str]** | | | | **model\_external\_id** | **str** | | | | **model\_provider\_name** | **str** | | | | **mapped\_model\_id** | **str** | | \[optional] | | **output\_format** | **str** | | \[optional] | | **deployment** | **str** | | | | **can\_take\_video\_as\_input** | **bool** | | | | **can\_take\_audio\_as\_input** | **bool** | | | | **can\_take\_image\_as\_input** | **bool** | | | | **can\_take\_text\_as\_input** | **bool** | | | | **can\_take\_action\_as\_input** | **bool** | | | | **is\_edge\_compatible** | **bool** | | | | **is\_cloud\_compatible** | **bool** | | | # MLModelUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/MLModelUpdateSchema # MLModelUpdateSchema ## Properties | Name | Type | Description | Notes | | -------------------------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **visibility** | **str** | | \[optional] | | **tags** | **List\[str]** | | \[optional] | | **model\_external\_id** | **str** | | \[optional] | | **model\_provider\_name** | **str** | | \[optional] | | **mapped\_model\_id** | **str** | | \[optional] | | **output\_format** | **str** | | \[optional] | | **deployment** | **str** | | \[optional] | | **can\_take\_video\_as\_input** | **bool** | | \[optional] | | **can\_take\_audio\_as\_input** | **bool** | | \[optional] | | **can\_take\_image\_as\_input** | **bool** | | \[optional] | | **can\_take\_text\_as\_input** | **bool** | | \[optional] | | **can\_take\_action\_as\_input** | **bool** | | \[optional] | # MLTrainingCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/MLTrainingCreateSchema # MLTrainingCreateSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **dataset\_uuid** | **str** | | | | **mlmodel\_uuid** | **str** | | | | **workspace\_uuid** | **str** | | | | **status** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # MLTrainingDeploySchema Source: https://docs.cyberwave.com/api-reference/rest/MLTrainingDeploySchema # MLTrainingDeploySchema ## Properties | Name | Type | Description | Notes | | --------------------- | -------------- | ----------- | ----------- | | **twin\_uuids** | **List\[str]** | | | | **environment\_uuid** | **str** | | | | **mlmodel\_uuid** | **str** | | \[optional] | # MLTrainingFailedCreationSchema Source: https://docs.cyberwave.com/api-reference/rest/MLTrainingFailedCreationSchema # MLTrainingFailedCreationSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **dataset\_uuid** | **str** | | | | **mlmodel\_uuid** | **str** | | | | **message** | **str** | | | # MLTrainingSchema Source: https://docs.cyberwave.com/api-reference/rest/MLTrainingSchema # MLTrainingSchema ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **dataset\_uuid** | **str** | | | | **mlmodel\_uuid** | **str** | | | | **created\_by\_uuid** | **str** | | | | **workspace\_uuid** | **str** | | | | **status** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | # MLTrainingUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/MLTrainingUpdateSchema # MLTrainingUpdateSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ---------------------- | ----------- | ----------- | | **status** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **update\_type** | **str** | | \[optional] | # MapCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/MapCreateSchema # MapCreateSchema Schema for creating/uploading a map. ## Properties | Name | Type | Description | Notes | | --------------------- | -------------------------------------------- | ----------- | ----------------------------- | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **map\_type** | **str** | | | | **resolution** | **float** | | \[optional] | | **origin\_x** | **float** | | \[optional] \[default to 0.0] | | **origin\_y** | **float** | | \[optional] \[default to 0.0] | | **origin\_z** | **float** | | \[optional] \[default to 0.0] | | **origin\_roll** | **float** | | \[optional] \[default to 0.0] | | **origin\_pitch** | **float** | | \[optional] \[default to 0.0] | | **origin\_yaw** | **float** | | \[optional] \[default to 0.0] | | **metadata** | [**Metadata**](/api-reference/rest/Metadata) | | \[optional] | # MapDataSchema Source: https://docs.cyberwave.com/api-reference/rest/MapDataSchema # MapDataSchema Schema for map data. ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **map\_type** | **str** | | | | **resolution** | **float** | | \[optional] | | **origin\_x** | **float** | | | | **origin\_y** | **float** | | | | **origin\_z** | **float** | | | | **origin\_roll** | **float** | | | | **origin\_pitch** | **float** | | | | **origin\_yaw** | **float** | | | | **data\_file\_uuid** | **str** | | | | **image\_width** | **int** | | \[optional] | | **image\_height** | **int** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | # MapStreamFinalizeSchema Source: https://docs.cyberwave.com/api-reference/rest/MapStreamFinalizeSchema # MapStreamFinalizeSchema Schema for finalizing a stream-started map with real file data. ## Properties | Name | Type | Description | Notes | | ----------------- | -------------------------------------------- | ----------- | ----------- | | **resolution** | **float** | | \[optional] | | **origin\_x** | **float** | | \[optional] | | **origin\_y** | **float** | | \[optional] | | **origin\_z** | **float** | | \[optional] | | **origin\_roll** | **float** | | \[optional] | | **origin\_pitch** | **float** | | \[optional] | | **origin\_yaw** | **float** | | \[optional] | | **metadata** | [**Metadata**](/api-reference/rest/Metadata) | | \[optional] | # MapStreamStartSchema Source: https://docs.cyberwave.com/api-reference/rest/MapStreamStartSchema # MapStreamStartSchema Schema for starting a map from a live stream. ## Properties | Name | Type | Description | Notes | | -------------- | --------- | ----------- | ----------- | | **twin\_uuid** | **str** | | | | **map\_type** | **str** | | | | **resolution** | **float** | | \[optional] | | **map\_name** | **str** | | \[optional] | # MapStreamStopSchema Source: https://docs.cyberwave.com/api-reference/rest/MapStreamStopSchema # MapStreamStopSchema Schema for requesting map finalization from a running edge node. ## Properties | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | # Metadata Source: https://docs.cyberwave.com/api-reference/rest/Metadata # Metadata ## Properties | Name | Type | Description | Notes | | ---- | ---- | ----------- | ----- | # MissionExecutionSchema Source: https://docs.cyberwave.com/api-reference/rest/MissionExecutionSchema # MissionExecutionSchema Schema for Mission execution response. ## Properties | Name | Type | Description | Notes | | ---------------------------- | ---------------------------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **mission\_uuid** | **str** | | | | **twin\_uuid** | **str** | | | | **task\_sequence\_snapshot** | **List\[Optional\[Dict\[str, object]]]** | | | | **parameters** | **Dict\[str, object]** | | | | **priority** | **int** | | \[optional] | | **start\_at** | **datetime** | | \[optional] | | **dry\_run** | **bool** | | | | **idempotency\_key** | **str** | | | | **current\_step** | **int** | | | | **status** | **str** | | | | **needs\_cancelled** | **bool** | | | | **created\_at** | **datetime** | | | | **started\_at** | **datetime** | | \[optional] | | **completed\_at** | **datetime** | | \[optional] | | **timeout** | **int** | | \[optional] | | **result** | **Dict\[str, object]** | | | # MissionSchema Source: https://docs.cyberwave.com/api-reference/rest/MissionSchema # MissionSchema Schema for Mission definition response. ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------------------------- | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **twin\_uuid** | **str** | | | | **task\_sequence** | **List\[Optional\[Dict\[str, object]]]** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | # MotionPlanSchema Source: https://docs.cyberwave.com/api-reference/rest/MotionPlanSchema # MotionPlanSchema @sync cyberwave-frontend/lib/types/motion.ts:MotionPlan ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------------------------------------------------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **steps** | [**List\[MotionPlanStepSchema\]**](/api-reference/rest/MotionPlanStepSchema) | | | # MotionPlanStepSchema Source: https://docs.cyberwave.com/api-reference/rest/MotionPlanStepSchema # MotionPlanStepSchema @sync cyberwave-frontend/lib/types/motion.ts:MotionPlanStep ## Properties | Name | Type | Description | Notes | | ------------------ | --------------------- | ----------- | --------------------------- | | **keyframe** | **str** | | \[optional] | | **joints** | **Dict\[str, float]** | | \[optional] | | **transition\_ms** | **int** | | \[optional] \[default to 0] | | **hold\_ms** | **int** | | \[optional] \[default to 0] | | **note** | **str** | | \[optional] | # MyFeaturesResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/MyFeaturesResponseSchema # MyFeaturesResponseSchema ## Properties | Name | Type | Description | Notes | | ------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **features** | [**List\[FeatureStatusSchema\]**](/api-reference/rest/FeatureStatusSchema) | | | | **is\_staff** | **bool** | | | # NavigationRotationSchema Source: https://docs.cyberwave.com/api-reference/rest/NavigationRotationSchema # NavigationRotationSchema ## Properties | Name | Type | Description | Notes | | ----- | --------- | ----------- | ----- | | **w** | **float** | | | | **x** | **float** | | | | **y** | **float** | | | | **z** | **float** | | | # NavigationWaypointSchema Source: https://docs.cyberwave.com/api-reference/rest/NavigationWaypointSchema # NavigationWaypointSchema @sync cyberwave-frontend/lib/types/navigation-types.ts:NavigationWaypoint ## Properties | Name | Type | Description | Notes | | ------------ | ---------------------------------------------------------------------------- | ----------- | ----------- | | **id** | **str** | | \[optional] | | **position** | **Dict\[str, float]** | | | | **rotation** | [**NavigationRotationSchema**](/api-reference/rest/NavigationRotationSchema) | | \[optional] | | **yaw** | **float** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # OccupancyMapCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/OccupancyMapCreateSchema # OccupancyMapCreateSchema Link an existing map (uploaded via POST /maps) to a locomotion twin and trigger the occupancy-map-tf MQTT notification. ## Properties | Name | Type | Description | Notes | | ------------- | ------- | ----------- | ----- | | **map\_uuid** | **str** | | | # OnboardingCompletionSchema Source: https://docs.cyberwave.com/api-reference/rest/OnboardingCompletionSchema # OnboardingCompletionSchema ## Properties | Name | Type | Description | Notes | | ------------- | -------- | ----------- | ----- | | **onboarded** | **bool** | | | # OrgFeatureSchema Source: https://docs.cyberwave.com/api-reference/rest/OrgFeatureSchema # OrgFeatureSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ------------ | ----------- | ----------- | | **uuid** | **str** | | | | **organization\_uuid** | **str** | | | | **organization\_name** | **str** | | | | **feature** | **str** | | | | **enabled** | **bool** | | | | **enabled\_by\_uuid** | **str** | | | | **enabled\_by\_email** | **str** | | | | **created\_at** | **datetime** | | | | **expires\_at** | **datetime** | | \[optional] | # OrgMemberSchema Source: https://docs.cyberwave.com/api-reference/rest/OrgMemberSchema # OrgMemberSchema ## Properties | Name | Type | Description | Notes | | ------------- | ------------------------------------------------------------------ | ----------- | ----- | | **user** | [**OrgMemberUserSchema**](/api-reference/rest/OrgMemberUserSchema) | | | | **role** | **str** | | | | **is\_owner** | **bool** | | | # OrgMemberUserSchema Source: https://docs.cyberwave.com/api-reference/rest/OrgMemberUserSchema # OrgMemberUserSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | \[optional] \[default to ''] | | **username** | **str** | | \[optional] \[default to ''] | | **email** | **str** | | \[optional] \[default to ''] | | **first\_name** | **str** | | \[optional] \[default to ''] | | **last\_name** | **str** | | \[optional] \[default to ''] | | **full\_name** | **str** | | \[optional] \[default to ''] | | **profile\_picture** | **str** | | \[optional] | # OrgMembersResponse Source: https://docs.cyberwave.com/api-reference/rest/OrgMembersResponse # OrgMembersResponse ## Properties | Name | Type | Description | Notes | | ----------- | ------------------------------------------------------------------ | ----------- | ----- | | **members** | [**List\[OrgMemberSchema\]**](/api-reference/rest/OrgMemberSchema) | | | # OrganizationCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/OrganizationCreateSchema # OrganizationCreateSchema ## Properties | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----------- | | **name** | **str** | | | | **slug** | **str** | | \[optional] | # OrganizationSchema Source: https://docs.cyberwave.com/api-reference/rest/OrganizationSchema # OrganizationSchema ## Properties | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **slug** | **str** | | | # OrganizationUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/OrganizationUpdateSchema # OrganizationUpdateSchema ## Properties | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----------- | | **name** | **str** | | | | **slug** | **str** | | \[optional] | # OrganizationWorkspaceSchema Source: https://docs.cyberwave.com/api-reference/rest/OrganizationWorkspaceSchema # OrganizationWorkspaceSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **slug** | **str** | | | | **organization** | **str** | | | | **owner** | **str** | | | | **owner\_name** | **str** | | | | **member\_count** | **int** | | | | **created\_at** | **str** | | | | **updated\_at** | **str** | | | # PairTwinSchema Source: https://docs.cyberwave.com/api-reference/rest/PairTwinSchema # PairTwinSchema Schema for pairing an edge to a twin. ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------- | ----------- | ----------- | | **twin\_uuid** | **str** | | | | **camera\_config** | **Dict\[str, object]** | | \[optional] | # PasswordChangeSchema Source: https://docs.cyberwave.com/api-reference/rest/PasswordChangeSchema # PasswordChangeSchema ## Properties | Name | Type | Description | Notes | | --------------------- | ------- | ----------- | ----- | | **current\_password** | **str** | | | | **new\_password** | **str** | | | # Payload Source: https://docs.cyberwave.com/api-reference/rest/Payload # Payload ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | | **var\_date** | **str** | | | # PermissionsSchema Source: https://docs.cyberwave.com/api-reference/rest/PermissionsSchema # PermissionsSchema ## Properties | Name | Type | Description | Notes | | ---------------------------- | -------- | ----------- | ------------------------------- | | **role** | **str** | | \[optional] | | **can\_view** | **bool** | | | | **can\_write** | **bool** | | | | **can\_admin** | **bool** | | | | **can\_delete** | **bool** | | | | **can\_create\_environment** | **bool** | | \[optional] \[default to False] | | **can\_rename\_environment** | **bool** | | \[optional] \[default to False] | | **can\_delete\_environment** | **bool** | | \[optional] \[default to False] | | **can\_create\_twin** | **bool** | | \[optional] \[default to False] | | **can\_delete\_twin** | **bool** | | \[optional] \[default to False] | # PipelineConfigSchema Source: https://docs.cyberwave.com/api-reference/rest/PipelineConfigSchema # PipelineConfigSchema ## Properties | Name | Type | Description | Notes | | ------------- | ---------------------------------------------------------------------------- | ----------- | ----- | | **pipelines** | [**List\[PipelineStagesSchema\]**](/api-reference/rest/PipelineStagesSchema) | | | # PipelineStagesSchema Source: https://docs.cyberwave.com/api-reference/rest/PipelineStagesSchema # PipelineStagesSchema ## Properties | Name | Type | Description | Notes | | --------------------- | -------------- | ----------- | ----- | | **opportunity\_type** | **str** | | | | **stages** | **List\[str]** | | | # PlanSchema Source: https://docs.cyberwave.com/api-reference/rest/PlanSchema # PlanSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **type** | **str** | | | | **organization** | **str** | | | # PopularTagSchema Source: https://docs.cyberwave.com/api-reference/rest/PopularTagSchema # PopularTagSchema ## Properties | Name | Type | Description | Notes | | --------- | ------- | ----------- | ----- | | **tag** | **str** | | | | **count** | **int** | | | # PopularTagsResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/PopularTagsResponseSchema # PopularTagsResponseSchema ## Properties | Name | Type | Description | Notes | | -------- | -------------------------------------------------------------------- | ----------- | ----- | | **tags** | [**List\[PopularTagSchema\]**](/api-reference/rest/PopularTagSchema) | | | # ProfileApi Source: https://docs.cyberwave.com/api-reference/rest/ProfileApi # cyberwave.rest.ProfileApi All URIs are relative to *[http://localhost](http://localhost)* | Method | HTTP request | Description | | ------------------------------------------------------------------------------------------------ | ----------------------------------------------- | ------------------- | | [**src\_users\_api\_profile\_change\_password**](#src_users_api_profile_change_password) | **PUT** /api/v1/users/@me/password/ | Change Password | | [**src\_users\_api\_profile\_complete\_onboarding**](#src_users_api_profile_complete_onboarding) | **POST** /api/v1/users/@me/onboarding/complete/ | Complete Onboarding | | [**src\_users\_api\_profile\_update\_profile**](#src_users_api_profile_update_profile) | **PATCH** /api/v1/users/@me/profile/ | Update Profile | # **src\_users\_api\_profile\_change\_password** > src\_users\_api\_profile\_change\_password(password\_change\_schema) Change Password Change the current user's password. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.password_change_schema import PasswordChangeSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.ProfileApi(api_client) password_change_schema = cyberwave.rest.PasswordChangeSchema() # PasswordChangeSchema | try: # Change Password api_instance.src_users_api_profile_change_password(password_change_schema) except Exception as e: print("Exception when calling ProfileApi->src_users_api_profile_change_password: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | ---------------------------- | -------------------------------------------------------------------- | ----------- | ----- | | **password\_change\_schema** | [**PasswordChangeSchema**](/api-reference/rest/PasswordChangeSchema) | | | ### Return type void (empty response body) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: Not defined ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_profile\_complete\_onboarding** > OnboardingCompletionSchema src\_users\_api\_profile\_complete\_onboarding() Complete Onboarding Mark the current user onboarding flow as completed. ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.onboarding_completion_schema import OnboardingCompletionSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.ProfileApi(api_client) try: # Complete Onboarding api_response = api_instance.src_users_api_profile_complete_onboarding() print("The response of ProfileApi->src_users_api_profile_complete_onboarding:\n") pprint(api_response) except Exception as e: print("Exception when calling ProfileApi->src_users_api_profile_complete_onboarding: %s\n" % e) ``` ### Parameters This endpoint does not need any parameter. ### Return type [**OnboardingCompletionSchema**](/api-reference/rest/OnboardingCompletionSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: Not defined * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # **src\_users\_api\_profile\_update\_profile** > ProfileResponseSchema src\_users\_api\_profile\_update\_profile(profile\_update\_schema) Update Profile Update the current user's profile (first\_name, last\_name, timezone). ### Example * Api Key Authentication (CustomTokenAuthentication): ```python theme={null} import cyberwave.rest from cyberwave.rest.models.profile_response_schema import ProfileResponseSchema from cyberwave.rest.models.profile_update_schema import ProfileUpdateSchema from cyberwave.rest.rest import ApiException from pprint import pprint # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. configuration = cyberwave.rest.Configuration( host = "http://localhost" ) # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. # Examples for each auth method are provided below, use the example that # satisfies your auth use case. # Configure API key authorization: CustomTokenAuthentication configuration.api_key['CustomTokenAuthentication'] = os.environ["API_KEY"] # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['CustomTokenAuthentication'] = 'Bearer' # Enter a context with an instance of the API client with cyberwave.rest.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = cyberwave.rest.ProfileApi(api_client) profile_update_schema = cyberwave.rest.ProfileUpdateSchema() # ProfileUpdateSchema | try: # Update Profile api_response = api_instance.src_users_api_profile_update_profile(profile_update_schema) print("The response of ProfileApi->src_users_api_profile_update_profile:\n") pprint(api_response) except Exception as e: print("Exception when calling ProfileApi->src_users_api_profile_update_profile: %s\n" % e) ``` ### Parameters | Name | Type | Description | Notes | | --------------------------- | ------------------------------------------------------------------ | ----------- | ----- | | **profile\_update\_schema** | [**ProfileUpdateSchema**](/api-reference/rest/ProfileUpdateSchema) | | | ### Return type [**ProfileResponseSchema**](/api-reference/rest/ProfileResponseSchema) ### Authorization CustomTokenAuthentication ### HTTP request headers * **Content-Type**: application/json * **Accept**: application/json ### HTTP response details | Status code | Description | Response headers | | ----------- | ----------- | ---------------- | | **200** | OK | - | # ProfileResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/ProfileResponseSchema # ProfileResponseSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----------- | | **uuid** | **str** | | | | **email** | **str** | | | | **first\_name** | **str** | | | | **last\_name** | **str** | | | | **profile\_picture** | **str** | | \[optional] | # ProfileUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/ProfileUpdateSchema # ProfileUpdateSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ----------- | | **first\_name** | **str** | | \[optional] | | **last\_name** | **str** | | \[optional] | | **timezone** | **str** | | \[optional] | # ProjectCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/ProjectCreateSchema # ProjectCreateSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ------- | ----------- | ----------------------------------- | | **name** | **str** | | | | **description** | **str** | | | | **workspace\_uuid** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] \[default to 'private'] | # ProjectSchema Source: https://docs.cyberwave.com/api-reference/rest/ProjectSchema # ProjectSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ------------ | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **workspace\_uuid** | **str** | | | | **organization\_uuid** | **str** | | | | **owner\_uuid** | **str** | | | | **visibility** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | # ProjectShareResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/ProjectShareResponseSchema # ProjectShareResponseSchema ## Properties | Name | Type | Description | Notes | | ----------- | ------- | ----------- | ----- | | **message** | **str** | | | | **role** | **str** | | | # PublicUserSchema Source: https://docs.cyberwave.com/api-reference/rest/PublicUserSchema # PublicUserSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ---------------------------- | | **uuid** | **str** | | | | **email** | **str** | | | | **first\_name** | **str** | | | | **last\_name** | **str** | | | | **full\_name** | **str** | | \[optional] \[default to ''] | | **profile\_picture** | **str** | | \[optional] | # QuaternionSchema Source: https://docs.cyberwave.com/api-reference/rest/QuaternionSchema # QuaternionSchema stub Quaternion rotation with explicit component fields. ## Properties | Name | Type | Description | Notes | | ----- | --------- | --------------- | ----- | | **w** | **float** | Real component. | | | **x** | **float** | X component. | | | **y** | **float** | Y component. | | | **z** | **float** | Z component. | | # RecordingGenerationRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/RecordingGenerationRequestSchema # RecordingGenerationRequestSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | # RecordingGenerationRequestSchemaByDate Source: https://docs.cyberwave.com/api-reference/rest/RecordingGenerationRequestSchemaByDate # RecordingGenerationRequestSchemaByDate ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **var\_date** | **str** | | | | **start\_timestamp** | **int** | | | | **end\_timestamp** | **int** | | | # RecordingGenerationResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/RecordingGenerationResponseSchema # RecordingGenerationResponseSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **task\_id** | **str** | | | | **status** | **str** | | | | **message** | **str** | | | # ReloadCapabilitiesBulkSchema Source: https://docs.cyberwave.com/api-reference/rest/ReloadCapabilitiesBulkSchema # ReloadCapabilitiesBulkSchema Schema for bulk reload capabilities request. ## Properties | Name | Type | Description | Notes | | --------------------- | -------------- | ----------- | ----------- | | **environment\_uuid** | **str** | | \[optional] | | **twin\_uuids** | **List\[str]** | | \[optional] | # RemoveMemberResponse Source: https://docs.cyberwave.com/api-reference/rest/RemoveMemberResponse # RemoveMemberResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | # Response Source: https://docs.cyberwave.com/api-reference/rest/Response # Response ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **dataset\_uuid** | **str** | | | | **mlmodel\_uuid** | **str** | | | | **created\_by\_uuid** | **str** | | | | **workspace\_uuid** | **str** | | | | **status** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **message** | **str** | | | # RevokeUserFeatureRequest Source: https://docs.cyberwave.com/api-reference/rest/RevokeUserFeatureRequest # RevokeUserFeatureRequest ## Properties | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **user\_uuid** | **str** | | | | **feature** | **str** | | | # RobotDescriptionSchema Source: https://docs.cyberwave.com/api-reference/rest/RobotDescriptionSchema # RobotDescriptionSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ---------------------------------------------------------- | ----------- | ----- | | **urdf\_content** | **str** | | | | **joints** | [**List\[JointSchema\]**](/api-reference/rest/JointSchema) | | | | **links** | **List\[Optional\[Dict\[str, object]]]** | | | # ShareSchema Source: https://docs.cyberwave.com/api-reference/rest/ShareSchema # ShareSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ---------------------------------- | | **user\_id** | **int** | | \[optional] | | **user\_email** | **str** | | \[optional] | | **team\_id** | **int** | | \[optional] | | **role** | **str** | | \[optional] \[default to 'reader'] | # SharesResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/SharesResponseSchema # SharesResponseSchema ## Properties | Name | Type | Description | Notes | | --------- | ------------------------------------------------------------------ | ----------- | ----- | | **users** | [**List\[UserShareSchema\]**](/api-reference/rest/UserShareSchema) | | | | **teams** | [**List\[TeamShareSchema\]**](/api-reference/rest/TeamShareSchema) | | | | **links** | [**List\[LinkShareSchema\]**](/api-reference/rest/LinkShareSchema) | | | # SimulationStartSchema Source: https://docs.cyberwave.com/api-reference/rest/SimulationStartSchema # SimulationStartSchema Schema for starting a simulation via the API. ## Properties | Name | Type | Description | Notes | | ---------------- | --------- | ----------- | ----------- | | **duration** | **float** | | \[optional] | | **stream\_data** | **bool** | | \[optional] | | **backend** | **str** | | \[optional] | # SlugAvailabilitySchema Source: https://docs.cyberwave.com/api-reference/rest/SlugAvailabilitySchema # SlugAvailabilitySchema ## Properties | Name | Type | Description | Notes | | ------------- | -------- | ----------- | ----- | | **available** | **bool** | | | | **slug** | **str** | | | # SyncWithAssetSchema Source: https://docs.cyberwave.com/api-reference/rest/SyncWithAssetSchema # SyncWithAssetSchema Schema for sync with asset response ## Properties | Name | Type | Description | Notes | | ------------------ | -------------- | ----------- | ----- | | **synced\_fields** | **List\[str]** | | | | **message** | **str** | | | # TaggedFramesCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/TaggedFramesCreateSchema # TaggedFramesCreateSchema Schema for creating TaggedFrames. ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **recording\_uuid** | **str** | | | | **frames** | **Dict\[str, object]** | | \[optional] | # TaggedFramesSchema Source: https://docs.cyberwave.com/api-reference/rest/TaggedFramesSchema # TaggedFramesSchema Schema for TaggedFrames response. ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **recording\_uuid** | **str** | | | | **created\_by\_uuid** | **str** | | \[optional] | | **updated\_by\_uuid** | **str** | | \[optional] | | **created\_at** | **str** | | | | **updated\_at** | **str** | | | | **frames** | **Dict\[str, object]** | | | # TaggedFramesUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/TaggedFramesUpdateSchema # TaggedFramesUpdateSchema Schema for updating TaggedFrames. ## Properties | Name | Type | Description | Notes | | ---------- | ---------------------- | ----------- | ----------- | | **frames** | **Dict\[str, object]** | | \[optional] | | **tags** | **Dict\[str, object]** | | \[optional] | # TaskExecutionSchema Source: https://docs.cyberwave.com/api-reference/rest/TaskExecutionSchema # TaskExecutionSchema Schema for TaskExecution response. ## Properties | Name | Type | Description | Notes | | ---------------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **task\_uuid** | **str** | | | | **task\_name** | **str** | | | | **twin\_uuid** | **str** | | | | **mission\_execution\_uuid** | **str** | | \[optional] | | **mission\_step** | **int** | | \[optional] | | **parameters** | **Dict\[str, object]** | | | | **status** | **str** | | | | **action\_id** | **str** | | | | **external\_reference** | **str** | | | | **created\_at** | **datetime** | | | | **started\_at** | **datetime** | | \[optional] | | **completed\_at** | **datetime** | | \[optional] | | **result** | **Dict\[str, object]** | | | | **error\_message** | **str** | | | # TaskSchema Source: https://docs.cyberwave.com/api-reference/rest/TaskSchema # TaskSchema Schema for Task response. ## Properties | Name | Type | Description | Notes | | ---------------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **task\_type** | **str** | | | | **controller\_policy\_uuid** | **str** | | \[optional] | | **default\_parameters** | **Dict\[str, object]** | | | | **workspace\_uuid** | **str** | | | | **visibility** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | # TaskStepSchema Source: https://docs.cyberwave.com/api-reference/rest/TaskStepSchema # TaskStepSchema Schema for a task step in a mission. ## Properties | Name | Type | Description | Notes | | -------------- | ---------------------- | ----------- | ----------- | | **task\_uuid** | **str** | | | | **parameters** | **Dict\[str, object]** | | \[optional] | # TeamMemberResponse Source: https://docs.cyberwave.com/api-reference/rest/TeamMemberResponse # TeamMemberResponse ## Properties | Name | Type | Description | Notes | | --------- | ------------------------------------------------ | ----------- | ----- | | **user** | [**UserSchema**](/api-reference/rest/UserSchema) | | | | **owner** | **bool** | | | | **role** | **str** | | | # TeamShareSchema Source: https://docs.cyberwave.com/api-reference/rest/TeamShareSchema # TeamShareSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------------ | ----------- | ----------- | | **team\_id** | **int** | | | | **team\_name** | **str** | | | | **role** | **str** | | | | **granted\_by** | **str** | | \[optional] | | **created\_at** | **datetime** | | | # TwinActionRequestSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinActionRequestSchema # TwinActionRequestSchema ## Properties | Name | Type | Description | Notes | | --------------------- | ------------------------------------------------------------ | ----------- | --------------------------------- | | **action\_type** | **str** | | | | **name** | **str** | | \[optional] | | **plan** | [**MotionPlanSchema**](/api-reference/rest/MotionPlanSchema) | | \[optional] | | **joints** | **Dict\[str, float]** | | \[optional] | | **scope** | **str** | | \[optional] \[default to 'auto'] | | **environment\_uuid** | **str** | | \[optional] | | **execution** | **str** | | \[optional] \[default to 'async'] | | **preview** | **bool** | | \[optional] \[default to False] | | **source\_type** | **str** | | \[optional] | | **tick\_ms** | **int** | | \[optional] | | **transition\_ms** | **int** | | \[optional] | | **hold\_ms** | **int** | | \[optional] | # TwinActionResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinActionResponseSchema # TwinActionResponseSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **action\_id** | **str** | | \[optional] | | **status** | **str** | | | | **message** | **str** | | \[optional] | | **plan** | **Dict\[str, object]** | | \[optional] | | **resolved\_scope** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # TwinActionStatusSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinActionStatusSchema # TwinActionStatusSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ------------------------------------------------------------ | ----------- | ----------- | | **action\_id** | **str** | | | | **status** | **str** | | | | **message** | **str** | | \[optional] | | **plan** | [**MotionPlanSchema**](/api-reference/rest/MotionPlanSchema) | | \[optional] | | **resolved\_scope** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **updated\_at** | **float** | | \[optional] | # TwinBindingSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinBindingSchema # TwinBindingSchema Schema for a twin binding (what twins an edge serves). ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------- | ----------- | ----- | | **twin\_uuid** | **str** | | | | **twin\_name** | **str** | | | | **camera\_config** | **Dict\[str, object]** | | | # TwinConnectionEventSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinConnectionEventSchema # TwinConnectionEventSchema Schema for twin connection events (edge telemetry) ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **timestamp** | **str** | | | | **event\_type** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **twin\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | # TwinCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinCreateSchema # TwinCreateSchema Schema for creating and updating a twin. ## Properties | Name | Type | Description | Notes | | ------------------------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **asset\_uuid** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **position\_x** | **float** | | \[optional] | | **position\_y** | **float** | | \[optional] | | **position\_z** | **float** | | \[optional] | | **rotation\_w** | **float** | | \[optional] | | **rotation\_x** | **float** | | \[optional] | | **rotation\_y** | **float** | | \[optional] | | **rotation\_z** | **float** | | \[optional] | | **scale\_x** | **float** | | \[optional] | | **scale\_y** | **float** | | \[optional] | | **scale\_z** | **float** | | \[optional] | | **kinematics\_override** | **Dict\[str, object]** | | \[optional] | | **joint\_calibration** | **Dict\[str, object]** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | | **controller\_policy\_uuid** | **str** | | \[optional] | | **attach\_to\_twin\_uuid** | **str** | | \[optional] | | **attach\_to\_link** | **str** | | \[optional] | | **attach\_offset\_x** | **float** | | \[optional] | | **attach\_offset\_y** | **float** | | \[optional] | | **attach\_offset\_z** | **float** | | \[optional] | | **attach\_offset\_rotation\_w** | **float** | | \[optional] | | **attach\_offset\_rotation\_x** | **float** | | \[optional] | | **attach\_offset\_rotation\_y** | **float** | | \[optional] | | **attach\_offset\_rotation\_z** | **float** | | \[optional] | | **fixed\_base** | **bool** | | \[optional] | # TwinDriverLogSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinDriverLogSchema # TwinDriverLogSchema Schema for persisted twin driver logs. ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **timestamp** | **str** | | | | **level** | **str** | | | | **message** | **str** | | | | **container\_name** | **str** | | \[optional] | | **source** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | | # TwinDriverLogsResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinDriverLogsResponseSchema # TwinDriverLogsResponseSchema Paginated response for twin driver logs. ## Properties | Name | Type | Description | Notes | | ------------- | -------------------------------------------------------------------------- | ----------- | ----- | | **items** | [**List\[TwinDriverLogSchema\]**](/api-reference/rest/TwinDriverLogSchema) | | | | **total** | **int** | | | | **limit** | **int** | | | | **offset** | **int** | | | | **has\_more** | **bool** | | | # TwinJointCalibrationSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinJointCalibrationSchema # TwinJointCalibrationSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ------------------------------------------------------------------------------------- | ----------- | ------------------------------------ | | **joint\_calibration** | [**Dict\[str, JointCalibrationSchema\]**](/api-reference/rest/JointCalibrationSchema) | | | | **robot\_type** | **str** | | \[optional] \[default to 'follower'] | # TwinMetricsQuerySchema Source: https://docs.cyberwave.com/api-reference/rest/TwinMetricsQuerySchema # TwinMetricsQuerySchema Schema for metrics query response. ## Properties | Name | Type | Description | Notes | | ------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **timestamp** | **str** | | | | **metrics** | **Dict\[str, object]** | | | # TwinMotionResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinMotionResponseSchema # TwinMotionResponseSchema ## Properties | Name | Type | Description | Notes | | --------------------- | --------------------------------------------- | ----------- | ----------- | | **twin\_uuid** | **str** | | | | **environment\_uuid** | **str** | | \[optional] | | **keyframes** | **List\[object]** | | | | **animations** | **List\[object]** | | | | **scopes** | **Dict\[str, Optional\[Dict\[str, object]]]** | | \[optional] | # TwinNavigationCommandSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinNavigationCommandSchema # TwinNavigationCommandSchema ## Properties | Name | Type | Description | Notes | | ---------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------- | ----------- | | **command** | **str** | | | | **position** | **List\[float]** | | \[optional] | | **rotation** | **List\[float]** | | \[optional] | | **yaw** | **float** | | \[optional] | | **waypoints** | [**List\[NavigationWaypointSchema\]**](/api-reference/rest/NavigationWaypointSchema) | | \[optional] | | **relative\_translation** | **List\[float] or Dict\[str, float]** | Relative \[dx, dy, dz] movement in meters for `relative_move`. | \[optional] | | **frame** | **str** | `body` for robot-local movement or `world` for fixed-map offsets. | \[optional] | | **controller\_policy\_uuid** | **str** | | \[optional] | | **reference\_frame** | **str** | | \[optional] | | **environment\_uuid** | **str** | | \[optional] | | **source\_type** | **str** | | \[optional] | | **constraints** | **Dict\[str, object]** | | \[optional] | | **metadata** | **Dict\[str, object]** | Use `{"units": "meters"}` with `relative_move`. | \[optional] | # TwinSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinSchema # TwinSchema ## Properties | Name | Type | Description | Notes | | ------------------------------- | ---------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **asset\_uuid** | **str** | | | | **environment\_uuid** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **glb\_file** | **str** | | | | **urdf\_file** | **str** | | | | **position\_x** | **float** | | | | **position\_y** | **float** | | | | **position\_z** | **float** | | | | **rotation\_w** | **float** | | | | **rotation\_x** | **float** | | | | **rotation\_y** | **float** | | | | **rotation\_z** | **float** | | | | **scale\_x** | **float** | | | | **scale\_y** | **float** | | | | **scale\_z** | **float** | | | | **joint\_states** | **Dict\[str, object]** | | \[optional] | | **kinematics\_override** | **Dict\[str, object]** | | \[optional] | | **joint\_calibration** | **Dict\[str, object]** | | \[optional] | | **metadata** | **Dict\[str, object]** | | | | **capabilities** | **Dict\[str, object]** | | | | **controller\_policy\_uuid** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] | | **attach\_to\_twin\_uuid** | **str** | | \[optional] | | **attach\_to\_link** | **str** | | \[optional] | | **child\_twin\_uuids** | **List\[str]** | | \[optional] | | **attach\_offset\_x** | **float** | | | | **attach\_offset\_y** | **float** | | | | **attach\_offset\_z** | **float** | | | | **attach\_offset\_rotation\_w** | **float** | | | | **attach\_offset\_rotation\_x** | **float** | | | | **attach\_offset\_rotation\_y** | **float** | | | | **attach\_offset\_rotation\_z** | **float** | | | | **fixed\_base** | **bool** | | | # TwinStateUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinStateUpdateSchema # TwinStateUpdateSchema ## Properties | Name | Type | Description | Notes | | --------------- | --------- | ----------- | ----------- | | **position\_x** | **float** | | \[optional] | | **position\_y** | **float** | | \[optional] | | **position\_z** | **float** | | \[optional] | | **rotation\_w** | **float** | | \[optional] | | **rotation\_x** | **float** | | \[optional] | | **rotation\_y** | **float** | | \[optional] | | **rotation\_z** | **float** | | \[optional] | # TwinTelemetryMetadataSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinTelemetryMetadataSchema # TwinTelemetryMetadataSchema ## Properties | Name | Type | Description | Notes | | --------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **twin\_uuid** | **str** | | | | **environment\_uuid** | **str** | | | | **metadata** | **Dict\[str, object]** | | | # TwinUniversalSchemaPatchSchema Source: https://docs.cyberwave.com/api-reference/rest/TwinUniversalSchemaPatchSchema # TwinUniversalSchemaPatchSchema Schema for patching twin universal schema. ## Properties | Name | Type | Description | Notes | | --------- | ---------- | ----------- | ----- | | **op** | **str** | | | | **path** | **str** | | | | **value** | **object** | | | # URDFProjectCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/URDFProjectCreateSchema # URDFProjectCreateSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------- | ----------- | ----------- | | **asset\_uuid** | **str** | | | | **main\_file\_path** | **str** | | \[optional] | # URDFProjectSchema Source: https://docs.cyberwave.com/api-reference/rest/URDFProjectSchema # URDFProjectSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------------ | ----------- | ----- | | **uuid** | **str** | | | | **slug** | **str** | | | | **asset\_uuid** | **str** | | | | **main\_file\_path** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | | | **updated\_by** | **str** | | | # UniversalSchemaPatchSchema Source: https://docs.cyberwave.com/api-reference/rest/UniversalSchemaPatchSchema # UniversalSchemaPatchSchema ## Properties | Name | Type | Description | Notes | | --------- | ---------- | ----------- | ----- | | **op** | **str** | | | | **path** | **str** | | | | **value** | **object** | | | # UpdateAlertSchema Source: https://docs.cyberwave.com/api-reference/rest/UpdateAlertSchema # UpdateAlertSchema Schema for updating an Alert. ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **media** | **str** | | \[optional] | | **alert\_type** | **str** | | \[optional] | | **severity** | **str** | | \[optional] | | **status** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # UpdateDatasetMetadataSchema Source: https://docs.cyberwave.com/api-reference/rest/UpdateDatasetMetadataSchema # UpdateDatasetMetadataSchema ## Properties | Name | Type | Description | Notes | | ------------------------------------ | ------- | ----------- | ----- | | **session\_name\_defined\_by\_user** | **str** | | | # UpdateMemberRoleRequest Source: https://docs.cyberwave.com/api-reference/rest/UpdateMemberRoleRequest # UpdateMemberRoleRequest ## Properties | Name | Type | Description | Notes | | -------- | ------- | ----------- | ----- | | **role** | **str** | | | # UpdateMemberRoleResponse Source: https://docs.cyberwave.com/api-reference/rest/UpdateMemberRoleResponse # UpdateMemberRoleResponse ## Properties | Name | Type | Description | Notes | | ----------- | -------- | ----------- | ----- | | **success** | **bool** | | | | **message** | **str** | | | | **role** | **str** | | | # UpdateRecordingMetadataSchema Source: https://docs.cyberwave.com/api-reference/rest/UpdateRecordingMetadataSchema # UpdateRecordingMetadataSchema ## Properties | Name | Type | Description | Notes | | ------------------------------------ | ------- | ----------- | ----- | | **session\_name\_defined\_by\_user** | **str** | | | # UpdateTaskSchema Source: https://docs.cyberwave.com/api-reference/rest/UpdateTaskSchema # UpdateTaskSchema Schema for updating a task. ## Properties | Name | Type | Description | Notes | | ---------------------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **controller\_policy\_uuid** | **str** | | \[optional] | | **default\_parameters** | **Dict\[str, object]** | | \[optional] | | **visibility** | **str** | | \[optional] | # UserFeatureSchema Source: https://docs.cyberwave.com/api-reference/rest/UserFeatureSchema # UserFeatureSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ------------ | ----------- | ----------- | | **uuid** | **str** | | | | **user\_uuid** | **str** | | | | **user\_email** | **str** | | | | **user\_name** | **str** | | | | **feature** | **str** | | | | **enabled** | **bool** | | | | **reason** | **str** | | | | **granted\_by\_uuid** | **str** | | | | **granted\_by\_email** | **str** | | | | **created\_at** | **datetime** | | | | **expires\_at** | **datetime** | | \[optional] | # UserSchema Source: https://docs.cyberwave.com/api-reference/rest/UserSchema # UserSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | -------- | ----------- | ----- | | **uuid** | **str** | | | | **username** | **str** | | | | **email** | **str** | | | | **is\_staff** | **bool** | | | | **waitlist** | **bool** | | | | **waitlist\_position** | **int** | | | | **banned** | **bool** | | | | **first\_name** | **str** | | | | **last\_name** | **str** | | | | **full\_name** | **str** | | | | **profile\_picture** | **str** | | | # UserSearchResultSchema Source: https://docs.cyberwave.com/api-reference/rest/UserSearchResultSchema # UserSearchResultSchema ## Properties | Name | Type | Description | Notes | | ------------- | -------- | ----------- | ----- | | **uuid** | **str** | | | | **email** | **str** | | | | **name** | **str** | | | | **is\_staff** | **bool** | | | # UserShareSchema Source: https://docs.cyberwave.com/api-reference/rest/UserShareSchema # UserShareSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------------ | ----------- | ----------- | | **user\_id** | **int** | | | | **username** | **str** | | | | **email** | **str** | | | | **role** | **str** | | | | **granted\_by** | **str** | | \[optional] | | **created\_at** | **datetime** | | | # VLMGenerationSchema Source: https://docs.cyberwave.com/api-reference/rest/VLMGenerationSchema # VLMGenerationSchema ## Properties | Name | Type | Description | Notes | | -------------- | ------- | ----------- | ----- | | **prompt** | **str** | | | | **image\_url** | **str** | | | # VLMResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/VLMResponseSchema # VLMResponseSchema ## Properties | Name | Type | Description | Notes | | ------------ | ------- | ----------- | ----- | | **response** | **str** | | | # Value Source: https://docs.cyberwave.com/api-reference/rest/Value # Value ## Properties | Name | Type | Description | Notes | | ---- | ---- | ----------- | ----- | # Vector3Schema Source: https://docs.cyberwave.com/api-reference/rest/Vector3Schema # Vector3Schema stub 3D vector with explicit coordinate fields. ## Properties | Name | Type | Description | Notes | | ----- | --------- | ------------- | ----- | | **x** | **float** | X coordinate. | | | **y** | **float** | Y coordinate. | | | **z** | **float** | Z coordinate. | | # VendorDescriptionSchema Source: https://docs.cyberwave.com/api-reference/rest/VendorDescriptionSchema # VendorDescriptionSchema ## Properties | Name | Type | Description | Notes | | --------------- | ------- | ----------- | ----------- | | **name** | **str** | | | | **description** | **str** | | | | **slug** | **str** | | | | **thumbnail** | **str** | | \[optional] | # Visibility Source: https://docs.cyberwave.com/api-reference/rest/Visibility # Visibility Visibility levels for objects. ## Enum * `PRIVATE` (value: `'private'`) * `LINK` (value: `'link'`) * `PROJECT` (value: `'project'`) * `WORKSPACE` (value: `'workspace'`) * `ORG` (value: `'org'`) * `PUBLIC` (value: `'public'`) # WorkflowConnectionCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowConnectionCreateSchema # WorkflowConnectionCreateSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | -------------------------------- | | **source\_node\_uuid** | **str** | | | | **target\_node\_uuid** | **str** | | | | **source\_output** | **str** | | \[optional] \[default to 'main'] | | **target\_input** | **str** | | \[optional] \[default to 'main'] | | **metadata** | **Dict\[str, object]** | | \[optional] | # WorkflowConnectionSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowConnectionSchema # WorkflowConnectionSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workflow\_uuid** | **str** | | | | **source\_node\_uuid** | **str** | | | | **target\_node\_uuid** | **str** | | | | **source\_output** | **str** | | | | **target\_input** | **str** | | | | **created\_at** | **datetime** | | | | **metadata** | **Dict\[str, object]** | | | # WorkflowCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowCreateSchema # WorkflowCreateSchema ## Properties | Name | Type | Description | Notes | | ------------------- | ---------------------- | ----------- | ----------------------------------- | | **name** | **str** | | | | **description** | **str** | | \[optional] \[default to ''] | | **is\_active** | **bool** | | \[optional] \[default to False] | | **workspace\_uuid** | **str** | | \[optional] | | **visibility** | **str** | | \[optional] \[default to 'private'] | | **metadata** | **Dict\[str, object]** | | \[optional] | # WorkflowExecuteSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowExecuteSchema # WorkflowExecuteSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ---------------------- | ----------- | ----------- | | **trigger\_data** | **Dict\[str, object]** | | \[optional] | # WorkflowExecutionSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowExecutionSchema # WorkflowExecutionSchema ## Properties | Name | Type | Description | Notes | | -------------------- | ------------------------------------------------------------------------------------------ | ----------- | ----------- | | **uuid** | **str** | | | | **workflow\_uuid** | **str** | | | | **status** | **str** | | | | **triggered\_by** | **str** | | | | **trigger\_data** | **Dict\[str, object]** | | | | **started\_at** | **datetime** | | | | **finished\_at** | **datetime** | | | | **error\_message** | **str** | | | | **metadata** | **Dict\[str, object]** | | | | **node\_executions** | [**List\[WorkflowNodeExecutionSchema\]**](/api-reference/rest/WorkflowNodeExecutionSchema) | | \[optional] | # WorkflowNodeCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowNodeCreateSchema # WorkflowNodeCreateSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ---------------------- | ----------- | ------------------------------- | | **name** | **str** | | | | **node\_type** | **str** | | | | **node\_subtype** | **str** | | \[optional] \[default to ''] | | **trigger\_type** | **str** | | \[optional] | | **parameters** | **Dict\[str, object]** | | \[optional] | | **position\_x** | **float** | | \[optional] \[default to 0] | | **position\_y** | **float** | | \[optional] \[default to 0] | | **notes** | **str** | | \[optional] \[default to ''] | | **is\_disabled** | **bool** | | \[optional] \[default to False] | | **metadata** | **Dict\[str, object]** | | \[optional] | # WorkflowNodeExecutionSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowNodeExecutionSchema # WorkflowNodeExecutionSchema ## Properties | Name | Type | Description | Notes | | ----------------------- | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **execution\_uuid** | **str** | | | | **node\_uuid** | **str** | | | | **status** | **str** | | | | **input\_data** | **List\[object]** | | | | **output\_data** | **List\[object]** | | | | **started\_at** | **datetime** | | | | **finished\_at** | **datetime** | | | | **error\_message** | **str** | | | | **execution\_time\_ms** | **int** | | | | **metadata** | **Dict\[str, object]** | | | # WorkflowNodeSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowNodeSchema # WorkflowNodeSchema ## Properties | Name | Type | Description | Notes | | ------------------ | ---------------------- | ----------- | ----- | | **uuid** | **str** | | | | **workflow\_uuid** | **str** | | | | **name** | **str** | | | | **node\_type** | **str** | | | | **node\_subtype** | **str** | | | | **trigger\_type** | **str** | | | | **parameters** | **Dict\[str, object]** | | | | **position\_x** | **float** | | | | **position\_y** | **float** | | | | **notes** | **str** | | | | **is\_disabled** | **bool** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **metadata** | **Dict\[str, object]** | | | # WorkflowNodeUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowNodeUpdateSchema # WorkflowNodeUpdateSchema ## Properties | Name | Type | Description | Notes | | ----------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **node\_type** | **str** | | \[optional] | | **node\_subtype** | **str** | | \[optional] | | **trigger\_type** | **str** | | \[optional] | | **parameters** | **Dict\[str, object]** | | \[optional] | | **position\_x** | **float** | | \[optional] | | **position\_y** | **float** | | \[optional] | | **notes** | **str** | | \[optional] | | **is\_disabled** | **bool** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # WorkflowSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowSchema # WorkflowSchema Workflow schema. ## Properties | Name | Type | Description | Notes | | ------------------- | ------------------------------------------------------------------------------------ | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **is\_active** | **bool** | | | | **workspace\_uuid** | **str** | | | | **visibility** | **str** | | | | **created\_at** | **datetime** | | | | **updated\_at** | **datetime** | | | | **created\_by** | **str** | | \[optional] | | **updated\_by** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | | | **nodes** | [**List\[WorkflowNodeSchema\]**](/api-reference/rest/WorkflowNodeSchema) | | \[optional] | | **connections** | [**List\[WorkflowConnectionSchema\]**](/api-reference/rest/WorkflowConnectionSchema) | | \[optional] | # WorkflowUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkflowUpdateSchema # WorkflowUpdateSchema ## Properties | Name | Type | Description | Notes | | --------------- | ---------------------- | ----------- | ----------- | | **name** | **str** | | \[optional] | | **description** | **str** | | \[optional] | | **is\_active** | **bool** | | \[optional] | | **visibility** | **str** | | \[optional] | | **metadata** | **Dict\[str, object]** | | \[optional] | # WorkspaceCreateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkspaceCreateSchema # WorkspaceCreateSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ------- | ----------- | ----------- | | **name** | **str** | | | | **description** | **str** | | \[optional] | | **slug** | **str** | | \[optional] | | **organization\_uuid** | **str** | | \[optional] | # WorkspaceResponseSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkspaceResponseSchema # WorkspaceResponseSchema ## Properties | Name | Type | Description | Notes | | ---------------- | ---------------------------------------------------------------- | ----------- | ------------------------------- | | **team** | [**WorkspaceSchema**](/api-reference/rest/WorkspaceSchema) | | | | **description** | **str** | | | | **slug** | **str** | | | | **owner** | **bool** | | \[optional] \[default to False] | | **organization** | [**OrganizationSchema**](/api-reference/rest/OrganizationSchema) | | | | **plan** | [**PlanSchema**](/api-reference/rest/PlanSchema) | | | # WorkspaceSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkspaceSchema # WorkspaceSchema ## Properties | Name | Type | Description | Notes | | ---------------- | -------------------------------------------------------------------------- | ----------- | ----------- | | **uuid** | **str** | | | | **name** | **str** | | | | **description** | **str** | | | | **organization** | **str** | | | | **slug** | **str** | | | | **users** | [**List\[WorkspaceUserSchema\]**](/api-reference/rest/WorkspaceUserSchema) | | | | **owner** | **str** | | | | **thumbnail** | **str** | | \[optional] | | **created\_at** | **str** | | | | **updated\_at** | **str** | | | | **metadata** | **Dict\[str, object]** | | | # WorkspaceUpdateSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkspaceUpdateSchema # WorkspaceUpdateSchema ## Properties | Name | Type | Description | Notes | | ---------------------- | ------- | ----------- | ----------- | | **name** | **str** | | | | **description** | **str** | | \[optional] | | **slug** | **str** | | \[optional] | | **organization\_uuid** | **str** | | \[optional] | # WorkspaceUserSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkspaceUserSchema # WorkspaceUserSchema ## Properties | Name | Type | Description | Notes | | --------- | ------------------------------------------------------------ | ----------- | ----- | | **user** | [**PublicUserSchema**](/api-reference/rest/PublicUserSchema) | | | | **owner** | **bool** | | | | **role** | **str** | | | # WorkspaceUsersSchema Source: https://docs.cyberwave.com/api-reference/rest/WorkspaceUsersSchema # WorkspaceUsersSchema Schema for listing users in a workspace for assignment dropdowns. ## Properties | Name | Type | Description | Notes | | --------- | ------- | ----------- | ----- | | **uuid** | **str** | | | | **name** | **str** | | | | **email** | **str** | | | # List environment recordings Source: https://docs.cyberwave.com/api-reference/rest/environment-recordings-list stub — GET `/api/v1/environments/{uuid}/recordings` `{/* stub — human curation pending */}` **Endpoint:** `GET /api/v1/environments/{environment_uuid}/recordings` * Returns **all** matching recordings in one response (**not paginated**). Payload: `{ "items": [...] }` (no `total` / `limit` / `offset`). * Each item is **lean** metadata (`uuid`, `twin_uuid`, `environment_uuid`, whitelisted `metadata`). Heavy playback payloads use `GET .../recordings/{recording_uuid}/data`. * **Optional query:** `start_timestamp` and `end_timestamp` as calendar dates `yyyy-mm-dd` (both required if filtering). The server returns recordings whose interval overlaps that UTC day range (inclusive start day through end day). * **Ordering:** Without date filters, items are sorted by server `timestamp` (newest first). With both date params, sorted by recording start time in metadata (newest first), then `timestamp`. # Credits & billing Source: https://docs.cyberwave.com/billing/credits Purchase credits and manage your account balance ## Purchasing Credits You can purchase credits directly from your organization's billing page to top up your account balance. ### Credit Top-up 1. Navigate to **Organization Settings** → **Billing** 2. Scroll to the **"Top Up Credits"** section 3. Enter the desired amount 4. Enter your credit card details using the secure payment form 5. Click **"Top Up Credits"** to complete the purchase Your credits will be added to your account balance immediately after payment confirmation. ### Downloading Invoices Each credit top-up paid by card generates a Stripe invoice. In **Organization Settings** → **Billing** → **Recent Transactions**, top-up rows show a download icon — click it to open the PDF invoice in a new tab. Only organization admins can download invoices. ### Payment Methods You can save multiple credit cards in your billing area: 1. Go to **Organization Settings** → **Billing** → **Payment Methods** 2. Your saved cards are listed with the last 4 digits 3. Click the trash icon to remove a card ## Redeeming Coupons To redeem a promotional coupon code for free credits: 1. Navigate to **Organization Settings** → **Billing** 2. Scroll to the **"Redeem Coupon"** section 3. Enter your coupon code 4. Click **"Redeem Coupon"** Each coupon code can only be redeemed once per organization. The credits will be instantly added to your balance. ## Credit Balance Your current credit balance is displayed at the top of the Billing tab. You can also view your full credit ledger to see all transactions and usage history. ### Low Balance Warning If credit enforcement is enabled and your balance drops below the warning threshold: * You'll see an amber warning at the top of the Usage page * A **"Top up credits"** link appears in the warning message * Clicking the link takes you directly to the top-up form ### Credit Status Credit statuses indicate enforcement state: * **Active**: Billing operations proceed normally * **Warning**: Balance is low (below warning threshold) * **Blocked**: Balance is exhausted, billable actions are halted An organization can also be **force-blocked** by Cyberwave staff regardless of its balance or whether credit enforcement is enabled. A force-block stays in effect until staff lift it. Contact support if your organization is blocked unexpectedly. ### Blocked Services Alert The first time you open the app in a session while your organization is blocked (or credits are running low), an alert lists which services are paused — AI agents, workflow execution, ML model inference, and asset operations — with a link to billing. The alert appears once per session. ## Pricing Credit pricing varies by operation type: * **Platform Events**: Billed based on active rate card (events, workflow runs, node executions, alerts) * **AI Usage**: based on provider-reported cost * **Storage**: Billed per GB-month at active storage rate View the Usage page in your organization settings to see current rates and historical charges. # Changelog Source: https://docs.cyberwave.com/changelog Product updates and announcements ## New Features * **Autonomous robot policy training**: Introduced an end-to-end foundation for training and deploying reinforcement-learning robot policies in Cyberwave Sim — a guided skill-teaching flow, automatic evaluation replays with measured acceptance evidence, and a trained-policy deployment handoff UX. Ships with initial coverage for Kinova arm manipulation, Go2/quadruped locomotion (including stair climbing), Boston Dynamics Spot autonomous mapping and navigation, and command-level drone flight policies (#4007). * **Occupancy map generation from authored environments**: New API to generate an occupancy/obstacle map directly from an environment's authored geometry, with a no-store preview option, so robots can be given a navigable map before any physical mapping run (#4084). * **Save and replay simulation runs**: Simulation sessions can now be saved as replays with streamlined viewer controls and smooth export, so a run can be reviewed after the fact instead of only watched live (#4066). * **Simulation view**: A running simulation now offers a "Simulation view" that streams MuJoCo's own physics-accurate render of the scene into the environment viewer, aimed freely by the browser — useful for seeing what the physics engine actually sees, even for robots with no camera of their own (#3978). * **Boston Dynamics Spot in simulation**: Added simulated support for the Boston Dynamics Spot quadruped, including runtime deployment wiring and autonomous mapping/navigation in Cyberwave Sim (#3998). * **Cyberwave iOS app with CyberScan**: Launched a new iOS app featuring CyberScan — LiDAR point-cloud capture, LiDAR mesh (GLB) capture, guided Object Capture, spatial capture filters with provenance, and environment-matching styling (#4019). * **GPS-referenced camera pose streaming**: DJI drone camera/gimbal pose can now be resolved against GPS and streamed as part of a twin's telemetry, along with a new partner video connector and a twin GPS-binding panel in the editor (#3933). * **Scene multiselect, groups, and spatial arrangement**: The environment editor now supports selecting multiple scene objects at once, grouping them, and arranging groups spatially, with a redesigned scene objects panel (#3989). * **GPS map waypoint authoring**: Waypoints can now be placed directly on the GPS map overlay in both edit and live mode (#4017). * **Move Twin area inspection missions**: Extended the Move Twin workflow node with reusable area-inspection missions, so a single authored area can be reused across multiple mission runs (#3887). * **Simulated acoustic sensors**: Added routing for simulated acoustic/audio sensors in Cyberwave Sim, including persisted audio recordings from simulated runs (#3847). * **Partner Agent-to-Agent (A2A) task API**: Partners can now submit a natural-language task over a JSON-RPC endpoint and receive a live streaming (SSE) progress feed as Cyberwave dispatches and executes it across one or more robots (#3858). * **Google Cloud Marketplace billing**: Added secure Google Cloud Marketplace purchase activation, organization linking, lifecycle reconciliation, and usage metering so customers can buy and manage Cyberwave through Google Cloud (#4170). * **Microsoft Marketplace billing**: Completed Microsoft Marketplace SaaS purchase validation, fulfillment, and usage metering, enabling customers to purchase and be billed for Cyberwave through Azure Marketplace (#3819). ## Feature Improvements ### Platform * **Explicit fixed-base control for procedural primitives**: Procedural primitives (spheres, cubes, walls, etc.) now have an explicit, discoverable "fixed base" toggle instead of relying on undocumented internal parameters, matching the control twins already had (#4047). * **Simulation view toggle**: Added a toggle, with per-environment persistence, to show or hide the live MuJoCo render during a simulation, independent of the reconstructed 3D scene view (#4032). * **Configurable range-sensor self-hit handling**: Range/LiDAR-style sensors can now be configured to re-cast beams that hit the robot's own geometry, so they report what's actually behind the robot instead of a self-hit (#4039). * **Dynamic simulation provisioning timeout**: Simulation startup timeout now scales with scene size (twin/camera count) instead of a flat window, so larger scenes get enough time to load instead of being killed by the watchdog prematurely (#3995). * **Executions gallery view**: The standalone Captures tab has been folded into Executions as a "Gallery" view, so browsing captures across runs and browsing run history now live in one place (#3953). * **Duplicate procedural primitives**: Procedural primitives in the environment editor can now be duplicated directly (#3958). * **Telemetry endpoint available outside active missions**: The telemetry streaming endpoint now works even when a robot is not currently running a mission, rather than only during one (#3939). * **Removed a duplicate keyboard controller panel**: The environment viewer no longer draws its own floating keyboard-controller overlay on top of the one already shown in the Controllers tab. ### Edge & Drivers * **Retired the `preview` message source type**: MQTT payloads now stamp `edit` for preview-mode authoring, and `preview` is no longer an accepted value. Preview mode itself is unchanged. Publishers still sending `preview` should switch to `edit`; see [source types](/api-reference/mqtt/main#source-types) for the seven supported values (#4015). * **Rail bogie controller**: Added a dedicated position-based controller for the rail bogie asset and tuned its control gains for the asset's real operating envelope (#3966, #3970). ### SDK * **Improved agent tool response serialization**: Fixed the SDK's object-to-JSON conversion so results returned through AI-assistant/agent tool calls carry the real object data instead of silently coming back as empty dictionaries (#4042). ## Bug Fixes * Restored Go2 mapping controls in Live mode after a regression, and surfaced mapping controls in Simulate mode too (#4088). * Fixed the DJI drone QR pairing flow and pairing dialog (#4089, #4085). * Fixed Move Twin workflows with "take picture on arrival" sometimes reporting failure even though the robot arrived and the photo was captured and uploaded successfully, affecting navigation-triggered captures on both edge and cloud execution (#4044, #4034, #4031, #4002). * Fixed workflow executions getting stuck or timing out because MQTT callback handling could block on the same thread needed to receive the very messages a workflow was waiting for (#4041, #4040). * Fixed stationary robotic arms crashing, or being routed to the wrong motion planner, when executing a Move Twin workflow: cloud/simulation inverse kinematics is now correctly scoped to simulation targets, and waypoints are rebased into the correct reference frame for live hardware (#3951, #3990). * Fixed Kinova arm waypoint navigation issues in Live mode (#4000). * Fixed a small jog command being rejected, and the arm not moving, when a continuous Kinova joint's commanded angle crossed the ±π wrap boundary (#3928). * Fixed users getting stuck indefinitely in the "try a real robot" queue in Labs when the associated edge device went offline, with no way for the queue to drain (#3981). * Fixed URDF/asset ZIP uploads failing when the archive contained symlinked files (#3722). * Raised the URDF ZIP upload size limit so large full-mesh robot assets such as the Unitree G1 are no longer rejected on import (#3721). * Fixed large URDF package uploads timing out during catalog sync because the signed-URL upload path allowed less processing time than the multipart path for the same server-side work (#3988). * Fixed multi-object OBJ mesh files only rendering their first object/group when exported into a MuJoCo simulation scene (#3977). * Fixed a memory leak in the environment viewer where 3D renderers and mesh geometry were not released on unmount, causing heap growth in scenes with many twins and camera views (#3945). * Fixed GPS telemetry incorrectly recording a "no fix" GPS reading as zero coordinates instead of null, which could look like a valid position at (0, 0) (#3930). * Fixed environment simulation preview thumbnails using an inconsistent zoom factor (#3959). * Fixed newly bootstrapped controller policies not getting a default simulation backend assigned to their linked assets, which could leave simulation policy resolution without a route (#4074). * Fixed the live camera-frame endpoint for MuJoCo simulations so frames are reliably available in both local and cloud scenarios (#4045). * Corrected the IMU driver example so it reports realistic source types instead of an invalid placeholder value (#4022). * Corrected the MQTT documentation, which had been recommending a placeholder broker username that could break authentication depending on deployment configuration (#3937). * Fixed a crash-on-exit in the Python SDK's Zenoh data bus backend when closing a connection with an in-flight publisher thread (#3984). * Fixed simulation recordings dropping or misaligning capture windows and sensor timestamps (#4072). ## New Features * **Locomotion RL policy for the Go2 in Cyberwave Sim**: Integrated a reinforcement-learning locomotion policy for the Unitree Go2 into Cyberwave Sim, bringing RL-driven walking to the simulated robot. * **Zero-copy data bus for co-located edge consumers**: The Python SDK's Zenoh data bus can now publish frames through shared memory instead of copying bytes, measured at 5-6x lower per-frame latency on Jetson hardware for same-host consumers. * **Colored mesh support in MuJoCo scene export**: Environments and twins using GLB assets with color textures now export those textures correctly into MuJoCo scenes, keeping simulated appearance in sync with the source mesh. ## Feature Improvements ### Platform * **Workspace admins can now invite and manage members**: Previously only workspace/organization owners could invite users; admins can now invite and manage members of workspaces they administer. * **Autosave for simulation stream profiles and the workflow editor**: The simulation stream profile panel and manager now autosave changes (debounced) with a live pending/saving/saved status indicator instead of requiring an explicit save action; the workflow editor was extended to use the same autosave mechanism. * **Clearer workflow run failures**: When an inline "Run workflow" action fails validation (e.g. a required input isn't mapped), the failure toast now shows the actual reason instead of a generic error. * **Primitive assets are easier to place**: Procedural primitives (spheres, cubes, walls, and other shapes) now spawn correctly grounded instead of half-buried, drag smoothly in the editor instead of jerking, and are auto-placed in a collision-free spot near the origin when created programmatically. * **Attachments carry integrity metadata**: Uploaded attachments now record a SHA-256 checksum and size at upload time, exposed via the API (#3357). ### Edge & Drivers * **OpenArm driver hardening**: Per-twin ROS 2 namespacing so topics no longer collide across robots on the same network, a substantially smaller Docker image, an updated SDK, and an explicit direct/MoveIt motion-controller selector. * **Kinova Gen3 reliability**: Fixed a boot-time race that could crash the driver on power-cycle, smoothed out teleop motion under CPU/timer jitter, and corrected the default camera sensor id used for pose estimation. * **UGV Beast streaming fix**: The UGV bridge now sources twin/environment/sensor identity from the edge-core twin configuration instead of the driver's local mapping file, fixing a mismatch that broke the camera WebRTC stream. * **SO-101 fixes**: Restored continuous hold-to-move keyboard teleop (a recent change had reduced it to one step per key press), and fixed a heartbeat regression that could show the robot as disconnected after edge-core updates. * **Go2 cloud simulation routing**: Go2 environment simulations now always run through the dedicated Go2 simulation runtime instead of occasionally falling back to a generic simulator profile (#3395). * **Workflow node fixes**: `object_pose`'s `target_frame` input is no longer silently ignored when configured through the node inspector, the node can also accept a fixed depth value as a stand-in when a depth sensor isn't available, and the `annotate` node now accepts raw camera frames in addition to encoded images. * **Media snapshot codec support**: Live camera snapshots now support VP8/VP9 streams in addition to H.264. ### SDK * **Python SDK**: Extracted reusable arm-driver building blocks (kinematics, joint control, motion shaping, teleop buffering) into the SDK, now used by the Piper driver and available to other arm integrations via the `cyberwave[drivers]` extra. * **Python SDK**: Added the Zenoh SHM zero-copy publish path described above under New Features. ## Bug Fixes * Fixed a crash when opening the inspector panel for a `move_waypoint` workflow node. * Fixed the Recorder workflow node not emitting telemetry start/stop for twins with no camera or microphone, so robot-only recordings are now captured correctly. * Fixed environments becoming invisible on the dashboard after their workspace was deleted, caused by a stale default-workspace reference. * Fixed asset updates with a duplicate registry alias returning a server error instead of a validation message. * Improved robot recording list query performance by using existing indexes and a read replica. ## Platform * **Audio recording is now decoupled from the live audio stream**: The microphone driver's `start_audio` / `stop_audio` commands on `cyberwave/twin/{uuid}/command` now drive **only** the WebRTC audio producer — no file is written as a side effect. The driver replies on `…/start_audio/status` (and `…/stop_audio/status`) with `{ "type": "audio_started" | "audio_stopped", "status": "ok" | "error", "source_type": "edge", "timestamp": … }`. This is symmetric with the camera driver's `start_video` / `stop_video` contract. * **Recording rides on `webrtc-command`**: Persisted audio recording is now controlled by `start_recording` / `stop_recording` published on `cyberwave/twin/{uuid}/webrtc-command` — the same topic and payload shape the Recorder workflow node already uses for video. The media-service SFU replies on `…/webrtc-command/status` with the authoritative `recording_id`. The frontend audio widget's REC button publishes there directly (no detour through the driver). The microphone driver also accepts `start_recording` / `stop_recording` on the command topic as a **fallback relay** for callers that don't speak `webrtc-command`; on that path the driver forwards verbatim to `webrtc-command` and lets media-service own the ACK. * **Audio widget has two independent controls**: The right-panel audio widget now exposes a **mic on/off** toggle (drives the live stream) next to the **REC** button (drives recording). Both flip to their "on" state only after the matching ACK arrives, so the indicators never lie about the underlying state. * **`auto_recording_audio` and `enable_recording` semantics preserved and tightened**: `CYBERWAVE_METADATA_AUTO_RECORDING_AUDIO=true` still sets `recording: true` on the **initial** WebRTC offer so recording auto-starts at startup; after that, recording is driven entirely by `start_recording` / `stop_recording`. `CYBERWAVE_METADATA_ENABLE_RECORDING=false` now silently drops only the driver's fallback relay — `start_audio` is unaffected, and frontend/Recorder publishes straight to `webrtc-command` (no longer gated by the driver flag). ## Docs * [Native Microphone Driver](/feature-reference/edge/drivers/native-microphone-driver) and the [generic-microphone driver README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-runtime/runtime-services/drivers/native/cyberwave/generic-microphone) document the two contracts and the fallback relay with concrete payloads. * [Recorder node](/feature-reference/workflows/recorder) cross-references the audio widget so it's clear all three callers (FE REC, Recorder node, driver fallback) converge on the same media-service handler and the same `webrtc-command/status` ACK. ## Platform * **Real-time alerts when the DJI driver refuses a command**: The Cyberwave Edge for DJI Android driver now raises a Cyberwave alert (`POST /api/v1/alerts`) every time it rejects a command before reaching the aircraft — missing `metadata.drivers.default.virtual_stick` opt-in, location permissions not granted, parked on a landing/RTH confirmation prompt. Each alert carries the `command`, an `error_code` (`VIRTUAL_STICK_OPT_IN_MISSING`, `PENDING_LANDING_CONFIRMATION`, …) and a remediation hint in the description, so the operator sees *why* a key press did nothing in the alerts panel instead of having to pull `adb logcat`. The existing `driver_action_failed` critical-alert path for SDK-level failures (takeoff / land / gimbal) is unchanged. * **No-motion watchdog for silently-capped commands**: The Virtual Stick send loop now compares the commanded body-frame linear velocity magnitude against `KeyAircraftVelocity` (NED) every tick, and fires a `driver_aircraft_not_moving` warning alert when the aircraft is reporting `isFlying = true` but observed velocity stays below 0.15 m/s for ≥ 2 s while the operator is commanding ≥ 0.4 m/s. The alert metadata carries the current `flight_mode`, GPS sat count + signal level, commanded vs observed velocity magnitudes, and the raw body-frame target — covering the cases where the MSDK's fire-and-forget `sendVirtualStickAdvancedParam` silently swallows commands (almost always indoor → no GPS lock, restricted-zone proximity, IMU heating, or low-battery saver). Rate-limited to one alert per stuck episode. * **Primary suspect surfaced in the alert name**: The `driver_aircraft_not_moving` alert ranks the most likely cause from telemetry and folds it into the alert *name*, so the operator sees the root cause in the alerts list without expanding the description. `Aircraft not moving (GPS-denied: 0 satellites)` is the indoor-flight case (the Mini 4 Pro requires GPS lock for sustained translational motion under Position mode; vertical still works because the barometer gives the FC an absolute altitude reference). `Aircraft not moving (FC in ATTI mode)` is the compass-interference / forced-ATTI case. `Aircraft not moving (cause unknown)` falls back to restricted-zone / IMU heating / battery saver / wind. The full description lead-paragraph repeats the suspect in human-friendly language with the matching remediation hint. * **No more spurious "RC reclaimed" log on every Virtual Stick arm**: MSDK pushes a `currentFlightControlAuthorityOwner = null` (mapped to `UNKNOWN` at our boundary) in the very first state update right after `enableVirtualStick.onSuccess`, before the FC has acknowledged authority transfer. The driver used to treat any non-MSDK authority — including `UNKNOWN` — as an RC reclaim and stopped the send loop, only for the next operator axis update to re-arm milliseconds later. The fix: only explicit `RC` / `OSDK` owners are genuine reclaims; `UNKNOWN` is "no signal yet". * **MQTT subscriber survives driver-side throws**: The driver's MQTT command dispatch is now wrapped in a top-level catch that fires a `driver_dispatch_exception` critical alert (with a truncated stack trace in the alert metadata) instead of letting an unchecked throw kill the subscription. A malformed payload or a transient SDK throw produces an alert and a logcat entry, and the next command on the same topic is dispatched normally. ## Docs * The [drones overview](/overview/drones) and the [Cyberwave Edge for DJI driver README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-nodes/cyberwave-edge-dji-mini-android) carry the full alert taxonomy (`driver_action_failed` / `driver_command_rejected` / `driver_aircraft_not_moving` / `driver_dispatch_exception` / `landing_confirmation_required`) and the operator's pre-flight reminder to keep the alerts panel open. ## New Features * **Off-RC teleoperation for DJI Mini (Virtual Stick)**: The Cyberwave Edge for DJI Android driver now routes continuous-stick commands (`move_forward` / `move_backward` / `strafe_*` / `turn_*` / `ascend` / `descend`) through DJI MSDK v5's Virtual Stick API, so the same SDK / keyboard surface used to drive the Go2 and the playground simulator drives the real aircraft too. Discrete actions (takeoff, land, RTH, gimbal, set home, compass calibration, reboot, emergency stop) were already wired and continue to work unchanged. ### Opt-in gate Off-RC teleop is opt-in per twin. Set the following on the twin metadata to enable it: ```json theme={null} { "drivers": { "default": { "virtual_stick": true } } } ``` Twins without the flag have continuous-stick commands rejected with a `failed` MQTT status — by design, so a phone that paired against a workspace-managed twin without the explicit opt-in cannot drive the aircraft. Discrete actions ship even without the gate. The `controller:dji-keyboard:v1` policy carries the requirement under `metadata.requires_twin_metadata`, so the UI can warn before the first keystroke when the gate is missing. ### Safety semantics and contention with the physical RC * **Stale-command decay.** Continuous targets decay to zero after **500 ms** without a fresh command (lost MQTT link or stuck key → aircraft hovers, not crashes). * **Auto-disable.** After **5 s** of continuous zero-velocity the driver hands stick authority back to the physical RC. * **The physical RC always wins.** Operator's hardware kill combo (CSC) and any RC stick input immediately reclaim authority — Virtual Stick yields silently. * **Automated motion isolates from VS.** Issuing `land` / `return_to_home` / `emergency_stop` shuts Virtual Stick down *before* the automated motion starts, so a stale continuous setpoint can never fight an automated descent. * **Active badge.** The frontend renders an **Off-RC teleop ACTIVE** badge whenever Virtual Stick owns the sticks, driven by the `cyberwave/twin//virtual_stick/status` MQTT topic. ## SDK ### Python SDK * **`FlyingTwin` continuous-stick verbs**: `FlyingTwin.move_forward` / `move_backward` / `turn_left` / `turn_right` / `strafe_*` / `ascend` / `descend` are now documented as driving the real DJI aircraft (given the opt-in) — the previous "DJI Mini driver currently drops them" caveat is gone. The `examples/drone_dji_mini.py` walkthrough was updated to demonstrate the live behaviour and the safety story. * **`FlyingTwin.pan_camera(angle_deg=…)`**: new high-level helper that pans the camera view by yawing the airframe. The Mini 4 Pro (and the rest of the Mini / Mavic Mini line) ships with a pitch-only mechanical gimbal, so the `yaw` axis on `gimbal_rotate` is silently ignored by the hardware — `pan_camera` is the supported way to change the camera heading on those aircraft. It re-sends `turn_left` / `turn_right` at 5 Hz inside the 500 ms command-stale watchdog and explicitly zeros the yaw axis when the target angle is reached. ## Docs * The [drones overview](/overview/drones) now documents the off-RC teleoperation opt-in flag, the safety story, and the RC-always-wins contention model alongside the existing PX4 / simulator continuous-stick path. * The [Cyberwave Edge for DJI driver README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-nodes/cyberwave-edge-dji-mini-android) carries the full Virtual Stick safety story, the W/S/A/D/Q/E/R/F keyboard layout, and the pre-flight checklist. ## New Features * **Edge workflow automation for spatial intelligence**: Added spatial zones, Timed Condition gates, edge-side dwell/timeout/debounce execution, live zone overlays, capture-frame authoring, and compile-time model compatibility checks for camera-frame workflows. This turns intrusion detection and zone-aware perception into an end-to-end workflow pattern across backend, frontend, edge workers, SDK channels, and docs (#2080, #2082, #2085, #2088, #2089, #2093, #2113, #2122, #2153, #2155, #2156). * **Datasets and robot recording playgrounds**: Introduced dataset import with Hugging Face/LeRobot focus, dataset slug/visibility/source metadata, SDK schema support, and visualizer/playground pages for LeRobot and Cyberwave-format datasets with episode playback, video panes, URDF/joint context, and long-recording streaming improvements (#2038, #2047, #2051, #2069). * **Commerce and template foundations**: Added asset pricing, currency selection, environment monthly cost previews, hardware purchase/rental guidance, organization billing details, delivery addresses, and richer environment/workflow template publishing and cloning flows (#2068, #2101, #2111, #2119, #2154). * **New edge/device integrations**: Added the first DJI Mini Android app with DJI telemetry, WebRTC video, Cyberwave MQTT/REST streaming, APK publishing, and smoke-test CI; added a native microphone driver with Whisper STT cloud-model wiring; added the PI05 OpenArm cloud node; and improved GO2 ROS 2 driver setup for dynamic IPs (#2096, #2117, #2004, #2026, #2097). ## Feature Improvements ### Platform * **Workflow authoring polish**: Workflow creation can start from templates or generated mission waypoints; the environment workbench, node library, canvas previews, node I/O strips, wired/available port grouping, missing-configuration hints, hover tooltips, and right-side inspector were substantially refined for faster graph authoring (#2048, #2052, #2065, #2077, #2079, #2081, #2086, #2087, #2115, #2120, #2123, #2128). * **Workflow semantics and edge sync clarity**: Workflows now derive environment behavior from bindings instead of the legacy `kind` field, support multi-twin perception on edge, publish `sync_workflows` immediately when run-on-edge workflows activate, and expose operator-triggered sync from the twin editor plus an `--edge-active` CLI filter (#2054, #2071, #2090, #2063, #2112, #2114). * **Environment and template UX**: The create-environment flow was redesigned into a full-screen multi-step experience, AI environment creation now opens the assistant on a blank environment, public templates clone correctly across workspaces, and template publishing supports public/workspace visibility with workflow summaries (#2053, #2059, #2060, #2119, #2154). * **Edge device observability**: The Edge Devices tab now follows live MQTT heartbeats, shows host/IP/uptime/stream health, filters archived tombstones, uses a compact row layout, and updates backend edge heartbeat state from `edge_health` messages (#2137, #2140, #2141). * **Model and catalog UX**: ML models now expose a typed edge runtime selector; the model picker has higher-contrast filters, tokenized search, and greys out edge-incompatible models in camera-frame chains with clear reasons and override affordances (#2076, #2146, #2155). * **Operator controls**: Added cloud-recording toggles per twin, an alert-overlay visibility toggle, live-mode hardware-dialog suppression when hardware already exists, improved onboarding overlay dark-mode readability, and route-safe environment creation redirects (#2046, #2095, #2147, #2151, #2158, #2145, #2099). ## SDK ### Python SDK * **Perception/runtime correctness**: ONNX YOLO postprocessing now applies per-class NMS; MQTT topic handlers are deduped to prevent WebRTC answer/candidate storms; annotate publishes overlay payloads on a dedicated frame overlay channel; and device fingerprinting has safer hostname fallbacks (#2133, #2153, #2140). * **Dataset and media support**: Python SDK schemas and bindings were updated for dataset import/visualization flows, and camera streaming paths gained stronger reconnect behavior for long-lived WebRTC sessions (#2038, #2051, #2069, #2130). * **Internal distribution hardening**: Video-sync packaging was obfuscated, CLI/internal install scripts gained better Buildkite authentication and redaction, and `sync-assets` can filter by `--registry-vendor` for workspace-scoped catalog syncs (#2036, #2157). ### C++ SDK * **API compatibility maintenance**: Updated the generated assets client call shape after pricing filters expanded the list-assets API, and kept C++ recording pipeline CI coverage aligned with the release (#2068). ## Bug Fixes * Fixed workflow execution reading stale replica data by forcing primary reads in workflow task paths. * Fixed missing `action_id` errors in generated `move_twin` workflow code. * Fixed workflow editor autosave races, Send Alert target-twin persistence, Timed Condition alias schema emission, node-title font/spacing issues, and spatial-filter inspector action layout. * Fixed AI environment creation hitting a shadowed backend endpoint, public template clone 403s, and wrong redirects after environment creation. * Fixed attachment ACL gaps, including environment-map parent access handling. * Fixed long robot recordings crashing playback by streaming signed Parquet data around the seek point. * Fixed edge worker install/build regressions by installing the local SDK wheel with required extras and smoke-testing `ultralytics`/`zenoh`. * Fixed edge workflow codegen bugs around detection confidence, empty twin UUID chains, spatial-filter bbox normalization, alert dedupe bypass for re-firing cooldowns, anonymize fail-closed behavior, and cloud-vs-edge model gate scope. * Fixed edge-core worker lifecycle issues: no unnecessary worker image pull when no active workflows exist, two-strike stale-worker cleanup, symmetric worker restart after edge-core restart, and graceful `docker stop` semantics. * Fixed CLI MQTT `topic_prefix` forwarding so workflow sync commands reach prefixed edge deployments. * Fixed camera driver WebRTC streams going silent after consumers disconnect, and fixed SDK MQTT handler accumulation that caused repeated WebRTC answers/candidates. * Fixed Edge Devices status drift, stale online fallbacks, cross-workspace tombstone visibility, and unresolved-edge status rendering. * Fixed GO2 driver dynamic-IP handling and filtering of simulated teleop commands. * Fixed the DJI Android smoke-test/degraded-mode path, Sentry empty-DSN startup crash, and CI emulator working-directory issues. * Fixed live-mode hardware dialog false positives by checking MQTT, REST, and historical edge-device presence. * Fixed onboarding overlay dark-mode contrast and removed an exposed close button. * Removed a sensitive token from Terraform configuration. ## New Features * **Multi-runtime Edge ML inference**: Edge workers can now run models through a runtime registry covering ONNX, TFLite (including quantized/INT8 paths), OpenCV DNN, TensorRT, and PyTorch, with normalized detection publishing across runtimes. * **Mission orchestration foundation**: Introduced the initial Mission model/renaming and planning primitives that connect mission authoring/execution flows across backend, frontend, and runtime paths. * **Replay intelligence overlays**: Added timeline event APIs and UI markers for alerts + telemetry, including twin-level filtering for replay investigations. * **Database-backed feature flag platform**: Replaced hardcoded flags with a DB catalog and added global, organization, and user-level rollout controls with explicit precedence. * **Uptime Kuma infrastructure**: Added a dedicated GCP Uptime Kuma stack with dev/staging/production environments and HTTPS-only access for platform monitoring. ## Feature Improvements ### Platform * **Shared-view performance and reliability**: Environment viewer requests now pass a dedicated view token header, isolate viewer query caches, and skip unnecessary data/subscriptions in view-only mode. * **Public website messaging polish**: Iterated homepage narrative and interactive hero/code showcase for a simpler, higher-clarity value proposition. * **Simulation and vision UX upgrades**: Improved virtual camera live-feed support and added camera FOV cone visualization in 3D environments. * **Catalog and seeding maintenance**: Refactored controller/model seed catalogs and updated OpenARM references for staging/prod compatibility. ## SDK ### Python SDK * **Regression hardening for critical paths**: Added integration coverage for `get_latest_frame()` image validity and slash-style `registry_id` twin resolution. * **Runtime protocol upgrades**: Backend MQTT client path moved to MQTT v5 semantics with expanded logging/reason-code handling. ### C++ SDK * **MQTT adapter modernization**: Transitioned from Paho to libmosquitto to improve maintainability and throughput behavior, especially for larger payload handling. * **Spec-alignment fixes**: Updated assets API client behavior to match current OpenAPI expectations. ## Bug Fixes * **Twin replay correctness on long recordings**: Fixed an issue where the digital twin would freeze or snap to a stale pose when scrubbing far from the currently-loaded segment of long robot recordings (90 min+ at 30 Hz). The replay timeline now greys out and shows a "Loading robot data..." indicator while the parquet window for the new segment is being fetched, and scrub clicks are ignored during the load to prevent racing the in-flight request. * **Replay parquet load time**: Robot recordings up to \~110 minutes at 30 Hz now load once (typically 1-3 seconds) and then scrub instantly across the entire recording. Previously, every scrub triggered a fresh range fetch that re-downloaded the parquet footer + dictionary pages, making large recordings feel "stuck". The play button is also no longer blocked on the initial fetch — playback starts immediately and the timeline overlay communicates the warm-up state. * **Replay spinner stuck on idle recordings**: Fixed an issue where loading a robot recording would leave the timeline frozen on "Loading robot data..." until the user clicked Play. The parquet loader now starts fetching the moment a recording is opened (not lazily on the first play tick), so the warm-up overlay clears as soon as the data is in cache. * **Multi-recording replay correctness**: Fixed two related bugs when multiple robot recordings are loaded together. Previously, only the first recording's parquet data was loaded (subsequent recordings for the same twin were silently discarded), and the timeline spinner would stay stuck forever when scrubbing to a segment belonging to a second recording. Parquet windows are now scoped per-recording, so every recording in a multi-session timeline loads and plays independently. The window cache also incrementally diffs across selection changes, so adding a recording to a multi-recording session no longer aborts and restarts the in-flight parquet fetch for the recording that was already loaded. * Removed MCP `cw_edit_position` 2m delta guardrail that was blocking large one-shot moves. * Fixed UGV replay recording path by ensuring sensor identity and sync-frame publication. * Fixed large ZIP asset sync regressions and added dedicated regression coverage for symlink/large-upload edge cases. * Fixed Python SDK crash when `environment_id`/`workspace_id` were passed explicitly to `Cyberwave()` * Fixed Python SDK asset lookup failure for slash-form registry IDs when aliases are present. * Fixed `Camera.start_streaming()` failures in notebook runtimes with active event loops. * Fixed controller-policy asset preselection clearing on edit due to loading/search timing. * Fixed edit-mode camera panel defaults and depth-visualization rendering conditions. * Fixed UGV driver reconnect stability and servo joint-state sync drift. * Fixed TFLite resize fallback in environments without Pillow/OpenCV dependencies. ## New Features * **3D editing keeps physics active for GLB and URDF twins**: Both `GLBAsset` and `URDFAsset` updated so Rapier rigid bodies remain mounted while edit gizmos are shown, instead of disabling physics during transforms. * **Editor-mode-only transform controls**: `EnvironmentViewer3D` now gates `isEditing` and `transformMode` with `isEditorMode`, preventing edit controls from appearing in non-editor contexts. ## Feature Improvements * **Safer pickability while gizmos are visible**: `setObjectTreePickable(...)` logic tightened in both asset renderers so object picking is disabled when transform gizmos are active, reducing accidental scene interaction conflicts. * **More predictable gizmo visibility outside editor mode**: New tests assert that selected GLB/URDF twins in simulate mode receive `isEditing: false` and `transformMode: undefined`, keeping gizmos hidden outside editor mode. * **Regression coverage for fixed-base physics in edit flows**: New GLB and URDF tests verify fixed-body Rapier behavior remains active while PivotControls are visible. ## New Features * **Mission authoring and execution upgrade**: Redesigned waypoint editing/ordering in UI, better waypoint visualization, drag-and-drop ordering, and waypoint-style in-scene transform gizmos for assets. * **Mission capture persistence + workflow integration**: Capture state and media now persist across backend, edge, and frontend; mission captures are surfaced in UI and connected to workflow attachment processing. * **Primitives as a first-class concept**: New public endpoint `GET /api/v1/assets/primitives`, SDK access via `cw.assets.list_primitives()`, MCP tooling, and docs updates for environment editing. * **Alert categories (business vs technical)**: Backend model/schema/migration/API updates, MQTT payload inclusion, Python SDK support, and docs update. * **GO2 runtime pipeline restoration**: End-to-end real-robot path and navigation timestamp handling updates under the new structure. ## Feature Improvements **SDK** * **Python SDK**: Added `AssetManager.list_primitives()` for alias-based primitive discovery (e.g. camera, lidar) with README usage examples. * **Python SDK alerts**: Category support added to alert create/update flows, aligned with backend alert categories. * **C++ SDK**: Core/runtime parity and route fixes, build/install/guard improvements, and README/docs refresh. **Platform** * **MQTT documentation**: Major rewrite of MQTT topic/payload reference with cross-linking from driver docs. * **Consistent "Add" menus**: Environment header and twin-list menus now share aligned items, icons, and action wiring. * **Controller selection UX**: Dedicated-first ordering, "See all" for universal controllers, and clearer "Unassign Controller" language/styling. ## Bug Fixes * **Replay timeline**: Resolved previously unclickable areas in the timeline. # Fleet provisioning Source: https://docs.cyberwave.com/enterprise/fleet-provisioning Install Edge Core on many devices without prompts, name them consistently, monitor them, restart them remotely, and control updates. **At a glance:** 30 min for the first device, then scripted · Advanced · Linux hosts (Ubuntu, Debian or Raspberry Pi OS; amd64 or arm64), root access, a service token, environments and twins created in advance. This page covers what a system integrator needs to roll out more than a handful of edge devices: a scripted install, golden images, naming, monitoring, remote restart, updates and decommissioning. The limits of scripted installs are listed first, because they shape the design. **Limits of a scripted install today:** * `--yes` binds **only the first edge-compatible twin** in the environment. A fully scripted install is reliable only when the environment has **one** edge-compatible twin. [Pairing more twins](#bind-more-than-one-twin) is a separate step. * On Linux, if the host has **more than one camera device** and a bound twin has a camera, the installer asks which camera to use. `--yes` does not skip this question. With exactly one camera, it picks that camera automatically. * `-e/--environment` only selects an environment. It never creates one. The environment must already exist in the token's workspace. * Without `-e`, `--yes` attaches to an environment the installer picks for you. Always pass `-e` when you provision devices. ## Plan before you install Create one environment per device, or per cell, with the twins that device drives. Each twin needs a Docker-based driver in its metadata (`docker_image` or `services`). Otherwise the installer does not offer it as an edge twin. You can create environments and twins from the web app, the SDK, or REST. Every environment and twin gets a slug in the form `{workspace}/{type}/{name}`, for example `acme/envs/line-3-cell-2`. Slugs are generated from names, and a collision gets a `-2` suffix. Pick a naming scheme such as site, line and cell before you create anything. [Slug system](/feature-reference/concepts/slug-system) In **Workspace settings → Tokens**, create a **service token**. It belongs to the workspace, holds its own role, and keeps working after the person who created it leaves. Use one token per customer workspace, or per site if you want to revoke sites independently. [API tokens](/feature-reference/api-tokens) ## Install one device headlessly Give the device a unique hostname. Edge Core's device fingerprint starts with the hostname. On Linux the installer needs root, and it installs Docker through `apt-get` if Docker is missing. ```bash theme={null} curl -fsSL https://cyberwave.com/install.sh | bash ``` Or install it from PyPI with `pip install cyberwave-cli`. ```bash Token from environment theme={null} # Keeps the token out of `ps` output and shell history export CYBERWAVE_API_KEY="cw_..." # injected by your secrets tooling sudo --preserve-env=CYBERWAVE_API_KEY \ cyberwave edge install -e acme/envs/line-3-cell-2 --yes ``` ```bash Token as a flag theme={null} # --token always wins over stored credentials and CYBERWAVE_API_KEY sudo cyberwave edge install \ --token "$CW_SERVICE_TOKEN" \ -e acme/envs/line-3-cell-2 \ --channel stable \ --yes ``` `cyberwave pair` is an alias of `cyberwave edge install` and takes the same options. ```bash theme={null} cyberwave edge status # is the service running? cyberwave edge whoami # device fingerprint and info cyberwave-edge-core status # credentials and MQTT connectivity (read-only) journalctl -u cyberwave-edge-core -f ``` The device then appears under **Workspace settings → Edges**. ### Installer options All options are listed by `cyberwave edge install --help`. | Option | What it does | Notes for fleets | | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `-y`, `--yes` | Skips confirmation prompts | Picks the first edge-compatible twin. It does not skip the Linux multi-camera question. | | `-e`, `--environment` | Environment to attach to, as a UUID or full slug (`acme/envs/production-floor`) | The name on its own is not enough. An unknown environment, or one in another workspace, stops the install before anything is installed. | | `--token` | API token to pair with | Overrides stored credentials and `CYBERWAVE_API_KEY`. An empty value (`--token "$UNSET"`) fails instead of falling back. A rejected token stops the install. | | `--channel` | `stable` (default), `dev` or `staging` | Selects the edge-core package channel | | `--version` | Exact edge-core version from the selected channel | Use it to pin a fleet to one tested version | | `--reconfigure-camera` | Re-runs camera detection only | Cannot be combined with `-e` or `--token` | | `--reconfigure-microphone`, `--reconfigure-speaker`, `--microphone-index` | Re-run macOS audio bridge setup | macOS only | | `--force-reinstall` | Rebuilds the USB/IP server | macOS only | Useful environment variables: | Variable | Effect | | ------------------------------------------- | --------------------------------------------------------------------- | | `CYBERWAVE_API_KEY` | Token used when no valid credentials are stored yet | | `CYBERWAVE_BASE_URL`, `CYBERWAVE_MQTT_HOST` | Point the device at a non-SaaS backend, such as a self-hosted server | | `CYBERWAVE_WORKSPACE_SLUG` | If it names a workspace other than the token's, a first install stops | | `CYBERWAVE_EDGE_CONFIG_DIR` | Config directory. Defaults to `~/.cyberwave/`. | ### Bind more than one twin A scripted install binds one twin. To bind more, you have two options. You can run the installer interactively once on that device. Or you can pair each extra twin through the REST API, then restart Edge Core so it starts the new drivers: ```bash theme={null} curl -X POST "https://api.cyberwave.com/api/v1/edges/$EDGE_UUID/pair" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"twin_uuid": "'"$TWIN_UUID"'"}' ``` Edge Core starts drivers for every twin linked to its fingerprint. Edge **workflow** sync, however, covers only the twins recorded in `environment.json` at install time. A twin paired later gets its driver but not its edge workflows. ## Golden images The installer and Edge Core write the device's identity and credentials to `~/.cyberwave/`: | File | Contents | | ------------------ | ------------------------------------------------------------------- | | `credentials.json` | API token and workspace. Mode `0600`. | | `fingerprint.json` | Device fingerprint, derived from hostname, MAC address and platform | | `environment.json` | Selected environment and twin UUIDs | | `edge.json` | Cached edge record, including camera mapping | If you clone an image that already contains these files, every clone shares one identity and one token. Build the golden image with the OS, Docker and the CLI, but **don't pair it**. Pair on first boot from your provisioning tool (cloud-init, Ansible, or a first-boot unit) after you set a unique hostname: ```bash theme={null} #!/usr/bin/env bash # First-boot provisioning. Runs as root. Values come from your provisioning system. set -euo pipefail hostnamectl set-hostname "$DEVICE_HOSTNAME" cyberwave edge install \ --token "$CW_SERVICE_TOKEN" \ -e "$ENV_SLUG" \ --channel stable \ --version "$EDGE_CORE_VERSION" \ --yes ``` If you use the [Cyberwave Raspberry Pi image](/feature-reference/edge/raspberry-pi), change the default SSH password and hostname it ships with before the devices leave your bench. ## Name and inventory devices * **Twins and environments** carry the slugs you planned, and those slugs appear in URLs, the SDK, the CLI and MCP tools. * **Edge records** have a `name` and `metadata` (`GET /api/v1/edges`, `PUT /api/v1/edges/{uuid}`). In the SDK, `cw.edges.list()` returns every edge the token can see. * **Host facts.** Every edge uploads host facts about every 30 s: CPU model, RAM, kernel, network interfaces, primary MAC address, board serial (Raspberry Pi, Jetson), active watchdogs, and the running Edge Core and SDK versions. Use the primary MAC for DHCP reservations and the serial for asset tracking. ## Monitor the fleet **Liveness.** Each edge shows one of three states: | State | Meaning | | ----------- | ------------------------------------------------------------------------ | | **Online** | A bound twin published an MQTT `edge_health` heartbeat within 60 s | | **Standby** | Edge Core posted a REST keepalive within 90 s, but no twin is publishing | | **Offline** | Neither signal arrived within its window | **Alerts raised by Edge Core.** `driver_starting` and `worker_starting` track startup and report image-pull progress. `driver_start_failure`, `driver_restart_loop`, `model_download_failure` and `worker_start_failure` report failures. List them with `GET /api/v1/alerts` and filter by `twin_uuid`, `environment_uuid`, `status` or `severity`. See [Alerts](/feature-reference/edge/drivers/alerts). **Routing alerts out.** Built-in routing to email, Slack or PagerDuty is not documented. One pattern to test: a workflow with an `alert` trigger, followed by `send_email` or an `http_request` to the tool's incoming webhook. Validate it in a test workspace before you rely on it. **Logs.** Driver container logs, including image-pull progress, are forwarded over MQTT to the twin's Logs tab ([driver logs](/feature-reference/environment-editor/driver-logs)). On the device, use `cyberwave edge logs -f` or `journalctl -u cyberwave-edge-core`. **Self-healing on the device.** The systemd unit runs with `Restart=always` and `WatchdogSec=60`. On boards with `/dev/watchdog`, such as every Raspberry Pi, Edge Core also drives the hardware watchdog. Edge Core protects itself from the OOM killer, and on hosts with 4 GB of RAM or less it caps worker memory. ## Restart an edge remotely ```bash theme={null} curl -X POST "https://api.cyberwave.com/api/v1/edges/$EDGE_UUID/restart-core" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" ``` The API publishes `{"command": "restart_edge_core"}` on the MQTT topic `edges/{edge_uuid}/command` and returns `success`, `edge_uuid`, `request_id`, `command` and `topic`. Edge Core then stops the worker, removes driver containers and cached twin files, downloads the environment again, and restarts drivers and the worker. The device must be connected to the broker to receive the command. On the device itself, `cyberwave edge restart` does the same through systemd. ## Updates and version pinning * **Channels.** `stable` installs tagged releases. `dev` and `staging` install separate prerelease packages (`cyberwave-edge-core-dev`, `cyberwave-edge-core-staging`) that conflict with each other. Use `stable` for customer sites. * **Pinning.** `--version` installs an exact version from the channel. Running the installer again with a new `--version` installs or upgrades to that version. Check the running version with `cyberwave-edge-core --version`, or read it from host facts. * **Rollout.** Automatic Edge Core updates, fleet-wide staged rollouts and rollback are not documented. Drive upgrades from your own configuration management, canary first. * **Worker image.** Mutable tags (`latest`, `dev`, `staging`, `nightly` and similar) are pulled on every worker restart. Immutable tags (versions, digests) are pulled only when missing. To pin one, set `CYBERWAVE_WORKER_IMAGE` in a systemd drop-in (`sudo systemctl edit cyberwave-edge-core`) and restart the service. ## Decommission a device 1. On the device, run `sudo cyberwave edge uninstall --yes`. This stops the service, removes the unit, and releases the twins the device was paired to, so they can pair elsewhere. 2. If the device had its own token, revoke it in **Workspace settings → Tokens**. Revoking a service token stops it at once and deactivates its identity. Revoked tokens stay listed for audit. 3. Delete the edge record if you no longer need it (`DELETE /api/v1/edges/{uuid}`). ## Next steps What each device must reach, including install and update hosts. Connect fleet events to your MES, WMS or ticketing tools. Service tokens, roles, scoping and revocation. Edge Core and the full `cyberwave edge` command set. # Integration surfaces Source: https://docs.cyberwave.com/enterprise/integration-surfaces Every way to connect business systems, agents and devices to Cyberwave, with when to use each, how it authenticates, and its status. Use this page to choose how each customer system talks to Cyberwave. One table covers every surface. The sections after it cover MQTT connection details and PLC, MES and WMS patterns. ## All surfaces at a glance | Surface | Use it when | Auth | Reference | | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | **REST API** (`https://api.cyberwave.com/api/v1/...`) | Request/response work from any language: create twins and environments, provision organizations, workspaces and members, trigger workflows, read alerts, manage edges | `Authorization: Bearer ` (the `Token` prefix is also accepted) | [API overview](/api-reference/overview) · [REST reference](/api-reference/overview) | | **Python SDK** (`pip install cyberwave`) | Python services and scripts. Wraps REST and MQTT. | `CYBERWAVE_API_KEY` | [Python SDK](/overview/tools/python-sdk) · [C++ SDK](/overview/tools/cpp-sdk) | | **CLI** (`cyberwave`) | Provisioning scripts, edge management, CI | Stored login, `CYBERWAVE_API_KEY`, or `--token` | [CLI](/overview/tools/cli) | | **MQTT** (`mqtt.cyberwave.com`) | Real-time telemetry and commands from a non-Python service, or a custom driver | API token as password. See [Connecting to MQTT](#connecting-to-mqtt). | [MQTT reference](/api-reference/mqtt/main) | | **Workflow triggers** (`webhook`, `mqtt`, `schedule`, `email`, `event`, `manual`) | Start a no-code automation from an external event | REST or SDK trigger: API token. Webhook: not documented. | [Workflow nodes](/overview/features/workflow-nodes) · [MQTT trigger](/feature-reference/workflows/mqtt-trigger) | | **Workflow outputs** (`http_request`, `send_email`, `send_mqtt`, `send_ros2`, `send_alert`) | Push results out of a workflow to an external API, email, a twin topic or ROS 2 | Configured on the node | [Workflow nodes](/overview/features/workflow-nodes) | | **Execution ingress** (MQTT) | Report runs of your own external process as workflow executions, so they appear on the Cyberwave timeline | Broker-level (MQTT credentials) | [Execution ingress](/feature-reference/workflows/execution-ingress) | | **A2A partner API** (`POST /api/v1/a2a`) | An external agent submits a natural-language task and follows it over SSE | Workspace-scoped API token with the `a2a` scope key | [A2A partner API](/api-reference/a2a-partner-api) | | **MCP server** (`https://mcp.cyberwave.com/mcp`, or self-hosted over stdio) | AI agents and IDEs (Claude, Cursor, any MCP client) operate environments, twins and workflows | `Authorization: Bearer ` | [MCP server](/overview/tools/mcp-server) (early access) | | **ROS 2** (`BaseROS2Driver`, `send_ros2` node) | The robot already speaks ROS 2. Bridge its topics into a twin, or publish typed messages from a workflow. | Runs as a driver under Edge Core with the driver's API key | [BaseROS2Driver](/feature-reference/edge/drivers/ros2-base-driver) · [UR Sim tutorial](/tutorials/ur-sim-cyberwave-driver) | | **Custom driver** (Docker image under Edge Core) | Any device with its own protocol: vendor SDK, serial, CAN, fieldbus gateway | `CYBERWAVE_API_KEY` injected into the container | [Writing compatible drivers](/feature-reference/edge/drivers/writing-compatible-drivers) | | **Zenoh–MQTT bridge** (`cyberwave.zenoh_mqtt`) | Forward selected local Zenoh channels to cloud MQTT, with a file-backed queue while offline | MQTT password = API key | [Zenoh–MQTT bridge](/overview/tools/zenoh-mqtt-bridge) | | **Cloud nodes** (`cyberwave-cloud-node`) | Run inference, training or simulation on your own GPU machines, commanded by the platform | `CYBERWAVE_API_KEY` | [Cloud node](/overview/tools/cloud-node) (early access) | | **Live video** (WebRTC) | Consume a twin's camera in your own app. There is no RTSP, HLS or WHEP output. | API token or user MQTT credentials for signaling | [Consume live video](/overview/tools/custom-webrtc-consumer) | | **Docker registry** (`registry.cyberwave.com`) | Distribute private driver and model images | API key via credential helper or `docker login` | [Docker registry](/feature-reference/docker-registry) (Enterprise) | For long-lived integrations, use a **service token** scoped to the customer's workspace, not a personal token. See [API tokens](/feature-reference/api-tokens). ## Connecting to MQTT These values come from the Python SDK (`cyberwave/config.py`, `cyberwave/mqtt/__init__.py`, `cyberwave/mqtt_identity.py`). | Setting | Value | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Host | `mqtt.cyberwave.com` | | Port | `8883`, MQTT over TLS. The SDK turns TLS on automatically for this port and verifies the server certificate. | | Browsers | `wss://mqtt.cyberwave.com` (MQTT over secure WebSocket) | | Password | Your API token | | Username | `cwh_` followed by the SHA-256 hex digest of the token. The SDK derives it for you. The broker refuses a username that does not hash to the token. | | Protocol | MQTT 3.1.1 by default. MQTT 5 with `CYBERWAVE_MQTT_PROTOCOL=5`. | | Client ID | Must be unique per connection. Keep it within 23 bytes for MQTT 3.1.1. | | Topic prefix | None in production. Other deployments may prefix every topic (`CYBERWAVE_MQTT_TOPIC_PREFIX`). | | Authorization | Checked per topic against the token's access to the twin or workflow. For WebRTC signaling, subscribing needs read access and publishing needs write access. | ```python theme={null} import hashlib import os import ssl import paho.mqtt.client as mqtt from paho.mqtt.enums import CallbackAPIVersion token = os.environ["CYBERWAVE_API_KEY"] username = "cwh_" + hashlib.sha256(token.encode("utf-8")).hexdigest() client = mqtt.Client(callback_api_version=CallbackAPIVersion.VERSION2, client_id="mes_bridge_01") client.username_pw_set(username=username, password=token) client.tls_set(cert_reqs=ssl.CERT_REQUIRED) client.on_message = lambda c, u, msg: print(msg.topic, msg.payload) client.connect("mqtt.cyberwave.com", 8883) client.subscribe("cyberwave/twin//position") client.loop_forever() ``` In Python, the SDK does all of this for you. Use `Cyberwave()` with `CYBERWAVE_API_KEY` set. ## PLC, MES and WMS **Status today:** Cyberwave ships **no built-in OPC UA, Modbus or VDA5050 driver**. Some older pages list these protocols as supported. That means you can bridge them with a driver you write, not that a driver exists. The SDK has an AMR edge-node base class (`cyberwave.edge.AMREdgeNode`) with adapter hooks and VDA5050 configuration fields. No VDA5050 adapter ships with it. These patterns are possible with the pieces that exist: Build a workflow whose actuation nodes move the twin (`twin_control`, `send_joint_commands`, `send_controller_command`). Start it from the business system through REST or the SDK: ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() # reads CYBERWAVE_API_KEY run = cw.workflows.trigger( "acme/workflows/pick-order", inputs={"order_id": "SO-1042", "bin": "A3"}, ) run.wait(timeout=300) print(run.status, run.result) ``` `cw.workflows.trigger` calls `POST /api/v1/workflows/{uuid}/trigger`, so any language can do the same over REST. A `webhook` trigger node is the alternative when the business system can only send an HTTP call. Its URL and authentication are not documented yet. End the workflow with an `http_request` node that calls the MES or WMS API. Alternatively, have your integration service poll the run (`run.wait()` / `GET /api/v1/workflows/executions/{execution_uuid}`), or subscribe to the twin's MQTT event topics. Write a [custom driver](/feature-reference/edge/drivers/writing-compatible-drivers): a Docker image that Edge Core runs next to the cell. Inside it, use an OPC UA or Modbus client library of your choice and map tags to the twin's MQTT topics. For small jobs, a `code` node runs your own Python on the edge worker. Keep the PLC as the source of truth for interlocks. Use `BaseROS2Driver` to forward ROS 2 topics into the twin with little code, and the `send_ros2` workflow node to publish typed messages back. Start from the [UR Sim tutorial](/tutorials/ur-sim-cyberwave-driver). Cyberwave does not replace the cell's safety system. Keep e-stops, safety interlocks and safety-rated stops in the PLC and the robot controller. The tutorials say it plainly: software-only stops are for convenience, not safety. ## Next steps Architecture, data flows and deployment options. Hosts and ports for each surface. Build a driver for a device Cyberwave doesn't support yet. Triggers, actions, and where each node runs. # Network and firewall requirements Source: https://docs.cyberwave.com/enterprise/network-and-firewall Every host, port and protocol Cyberwave uses, per component, plus a copy-paste egress allowlist for SaaS deployments. Use this page to get firewall changes approved for a Cyberwave deployment. Every connection is **opened outbound** by the edge, the browser, or your application. In a SaaS deployment the customer network generally needs no inbound rules. Values on this page come from the SDK and CLI source and the existing reference pages. Anything not yet documented is called out. ## Summary allowlist (SaaS) This is the minimum egress for an edge node that streams video and runs edge workflows. Add the operator and developer rows from the tables below as needed. ```text theme={null} # Edge node: runtime (always) api.cyberwave.com TCP 443 HTTPS (REST) mqtt.cyberwave.com TCP 8883 MQTT over TLS # Edge node: live video and audio tls.turn.cyberwave.com TCP 443 TURN over TLS (default relay) turn.cyberwave.com UDP 3478 STUN # Edge node: container images (first start, updates, mutable tags) registry-1.docker.io TCP 443 Docker Hub registry auth.docker.io TCP 443 Docker Hub auth # Docker Hub also serves image layers from a CDN host. Use Docker's published allowlist. # Edge node: install and upgrade cyberwave.com TCP 443 CLI install script packages.buildkite.com TCP 443 edge-core apt repository and signing key pypi.org TCP 443 pip installs files.pythonhosted.org TCP 443 pip installs # Edge node: model weights (only when workflows load models that are not pre-staged) static.cyberwave.com TCP 443 Cyberwave-hosted ONNX weights ``` ## Edge node ### Runtime | Destination | Port / protocol | Purpose | Required when | | ------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | `api.cyberwave.com` | TCP 443, HTTPS | Registration, keepalive (`POST /api/v1/edges/discover` about every 30 s), environment and twin download, workflow sync, model catalog | Always | | `mqtt.cyberwave.com` | TCP 8883, MQTT over TLS | Commands, telemetry, edge health, WebRTC signaling, remote restart and sync commands | Always | | `tls.turn.cyberwave.com` | TCP 443, TURN over TLS (`turns:`) | Media relay for live video and audio. This is the SDK default. | Streaming | | `turn.cyberwave.com` | UDP 3478, STUN | Discovers the public address for a direct media path. Optional, because the TLS relay connects without it. | Streaming | | `turn.cyberwave.com` | UDP/TCP 3478, plus UDP 49152–65535 relay range | TURN over UDP | Only if you opt in with `CYBERWAVE_WEBRTC_TURN_URL=turn:turn.cyberwave.com:3478` | | Docker Hub | TCP 443 | Driver and worker images (`cyberwaveos/*`) | First start of each driver, and every worker restart on a mutable tag | | `registry.cyberwave.com` | TCP 443 | Private driver and model images | Only if your organization uses the [Cyberwave Docker Registry](/feature-reference/docker-registry) (Enterprise) | #### Why TLS on 443 for the relay The SDK uses exactly one TURN server. It picks TLS on port 443 on purpose, because that port gets through corporate and industrial firewalls that block 3478 and outbound high UDP ports. The trade-off is that relayed media runs over TCP, which adds latency under packet loss. If the site allows UDP, set `CYBERWAVE_WEBRTC_TURN_URL=turn:turn.cyberwave.com:3478` on the edge and open the UDP relay range instead. ### Model weights Edge Core fetches weights only for models that edge workflows load. It tries these sources in order and caches the result in `~/.cyberwave/models/`: 1. A Cyberwave-hosted signed URL. 2. The upstream URL on the catalog entry. Cyberwave's ONNX exports are on `static.cyberwave.com`. Community checkpoints can point to other hosts. 3. A runtime-managed download. For Ultralytics `.pt` models this means GitHub releases. To avoid all three, pre-stage the weight files. Edge Core then never contacts the catalog for those models. See [Model cache](/feature-reference/workflows/workers/model-cache). ### Installation and upgrades | Destination | Port | Purpose | | ----------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `cyberwave.com` | TCP 443 | `install.sh` for the CLI. `install-cloud-node.sh` for cloud nodes. | | `packages.buildkite.com` | TCP 443 | apt repository and GPG key for `cyberwave-edge-core` (and `cyberwave-cloud-node`). Prerelease `dev` and `staging` channels come from the same host. | | `pypi.org`, `files.pythonhosted.org` | TCP 443 | `pip install cyberwave-cli`. `cyberwave-edge-core` on platforms without apt. | | Docker's package repository and your OS mirrors | TCP 443 / 80 | On Linux, the installer installs Docker through `apt-get` if it is missing. | | `static.cyberwave.com` | TCP 443 | Raspberry Pi OS images, if you flash the [Cyberwave Pi image](/feature-reference/edge/raspberry-pi) | ### On the site network | Traffic | Port / protocol | When | | --------------------------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------- | | Zenoh peer discovery between containers on one edge | UDP multicast, local subnet | Always, on the host. No firewall change is needed for a single node. | | Zenoh router between edge hosts | TCP 7447 | Only if drivers are split across several hosts on the site | | Edge to robot or device | Driver-specific (serial, USB, CAN, ROS 2 DDS, or vendor IP ports) | Check the driver's documentation | ## Operator browser | Destination | Port / protocol | Purpose | | ---------------------- | ---------------------------------------------- | ------------------------------- | | `cyberwave.com` | TCP 443 | Web app | | `api.cyberwave.com` | TCP 443 | REST | | `mqtt.cyberwave.com` | TCP 443, MQTT over secure WebSocket (`wss://`) | Live state and WebRTC signaling | | Media service and TURN | WebRTC | Live video | ## Your applications and developer machines | Destination | Port / protocol | Purpose | | --------------------------- | ----------------------- | ---------------------------------------------------------------------------- | | `api.cyberwave.com` | TCP 443 | REST, Python SDK, CLI | | `mqtt.cyberwave.com` | TCP 8883, MQTT over TLS | SDK real-time calls: joint control, subscriptions | | `mcp.cyberwave.com` | TCP 443 | Hosted [MCP server](/overview/tools/mcp-server) (`/mcp`, Streamable HTTP) | | TURN hosts, as for the edge | See above | SDK video consumers (`twin.camera.get_video()`) | | `stun.l.google.com` | UDP 19302, STUN | The SDK video consumer adds this public STUN server to its ICE configuration | ## Cloud nodes A [cloud node](/overview/tools/cloud-node) connects outbound to the MQTT broker and needs no inbound ports. | Destination | Port | Purpose | | ----------------------------------------------- | ------------------------------------------- | ---------------------------- | | `mqtt.cyberwave.com` | TCP 8883 (MQTT over TLS) or 1883, see below | Workload commands and status | | `api.cyberwave.com` | TCP 443 | Registration and logs | | `packages.buildkite.com`, `cyberwave.com`, PyPI | TCP 443 | Install | The cloud node page lists `1883` as the default MQTT port. The SDK default is `8883` with TLS. Check which port your cloud node version uses (`CYBERWAVE_MQTT_PORT`) before you request firewall changes, and prefer TLS. ## Self-hosted server The self-hosted package exposes these services on the server: web frontend, REST API, MQTT for edges, MQTT over WebSocket for browsers, the media service, and a UDP range for WebRTC media (50000–50100). The reference configuration serves them without TLS. Put a TLS-terminating proxy in front and agree the final port plan with Cyberwave. Keep the task monitor (Celery Flower) off any customer-facing network. Even when self-hosted, the media service's ICE configuration points at Cyberwave's hosted STUN/TURN (`turn.cyberwave.com`) and a public Google STUN server. A self-hosted server therefore still needs egress for video unless you replace them. It also pulls images from Docker Hub, and syncing the catalog from production needs internet access. ## Port ranges you may see elsewhere Two different UDP ranges appear in Cyberwave material. They belong to different components: | Range | Component | | --------------- | ----------------------------------------------------------------------------------------------------- | | UDP 49152–65535 | Relay ports of the hosted TURN server (`turn.cyberwave.com`). Used only on the opt-in UDP relay path. | | UDP 50000–50100 | Media ports of the self-hosted media service | TCP 5349 (TURN over TLS) appears only in the self-hosted material. The SaaS SDK default is TURN over TLS on **443** at `tls.turn.cyberwave.com`. ## Proxies and TLS inspection * **HTTP(S) proxy.** Proxy support for Edge Core, drivers and the MQTT connection is not documented. MQTT on 8883 is a direct TLS connection and does not go through an HTTP proxy. Plan for direct egress from the edge VLAN. * **TLS inspection.** The SDK verifies the broker certificate (`CERT_REQUIRED`). If the network re-signs TLS, set `CYBERWAVE_MQTT_TLS_CA_CERT` to your CA bundle for SDK clients. Otherwise, exempt `mqtt.cyberwave.com` from inspection. ## Bandwidth Per-stream bandwidth is not documented in general. One driver gives a data point: the Go2 [navigation driver](/api-reference/autonomous-navigation-driver) exposes `CYBERWAVE_H264_BITRATE_KBPS`, which defaults to 2500 kbps per H.264 stream. Video goes up only while someone is viewing, recording, or running a cloud consumer. Edge workflows on `camera_frame` process frames locally. ## Next steps Architecture, data flows and deployment options. Headless installs, naming, monitoring and updates. Which endpoint to use for each business system. How WebRTC, MQTT and Zenoh fit together. # Cyberwave for integrators Source: https://docs.cyberwave.com/enterprise/overview Architecture, data flows and deployment options for solutions architects and IT/security teams evaluating Cyberwave. This section is for solutions architects at system integrators and for the customer's IT and security teams. It covers what runs where, which connections each component opens, and what exists today. Where something is not available or not documented yet, the page says so. ## Architecture Cyberwave has three parts. The **cloud control plane** is operated by Cyberwave. **Edge nodes** are Linux hosts that you run next to the robots. **Your applications** can run anywhere. The edge opens every connection outbound, so the site network generally needs no inbound firewall rules. ```mermaid theme={null} flowchart LR subgraph apps["Your applications"] sdk["Python SDK · scripts"] ext["MES · WMS · ERP"] agent["AI agents (MCP)"] browser["Operator browser"] end subgraph cloud["Cyberwave cloud (control plane)"] api["REST API"] broker["MQTT broker"] wf["Cloud workflow runner"] sfu["Media service (WebRTC SFU)"] turn["TURN relay"] store[("Storage: recordings,
datasets, model weights")] mcp["MCP server"] end subgraph site["Customer site"] subgraph edge["Edge node"] core["Edge Core (systemd)"] drv["Driver containers"] wk["Worker container
(edge workflows, models)"] bus(("Zenoh
local bus")) end hw["Robots · cameras · sensors"] end gpu["Cloud node
(your GPU host)"] sdk -- "HTTPS" --> api sdk -- "MQTT/TLS" --> broker ext -- "HTTPS" --> api agent -- "HTTPS" --> mcp --> api browser -- "HTTPS · WSS" --> api browser -- "WebRTC" --> sfu core -- "HTTPS" --> api core -- "MQTT/TLS" --> broker drv -- "MQTT/TLS" --> broker drv -- "WebRTC (TURN relay if needed)" --> sfu turn -.- sfu drv <--> bus <--> wk drv -- "serial · USB · CAN · ROS 2 · IP" --> hw core -- "HTTPS" --> store wf --> broker gpu -- "MQTT/TLS" --> broker ``` ## What runs where | Component | Runs on | Operated by | What it does | | ----------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Web app, REST API, MQTT broker, cloud workflow runner | Cyberwave cloud | Cyberwave | Twins, environments, workflows, alerts, users, tokens. The broker carries commands, telemetry and WebRTC signaling. | | Media service (SFU) and TURN relay | Cyberwave cloud | Cyberwave | Receives live video from edges and fans it out to browsers and SDK consumers. | | Hosted MCP server | Cyberwave cloud (`mcp.cyberwave.com`) | Cyberwave | Exposes platform operations as tools for AI agents. It can also be self-hosted. | | **Edge Core** | Your Linux host at the site. macOS is also supported (launch agent). | You | A systemd service (`cyberwave-edge-core`). It registers the device, starts driver and worker containers, downloads model weights, and runs the watchdogs. | | **Drivers** | Docker containers on the edge node | You (images from Cyberwave or your own) | Translate the device's native interface into Cyberwave MQTT topics. Edge Core starts a driver for each linked twin. Multi-container drivers are supported. | | **Worker container** | Docker container on the edge node | You | Runs edge workflows and AI models next to the camera. | | **Cloud nodes** | Any machine you run, usually with a GPU | You | Take inference, training and simulation workloads from the platform over outbound MQTT. See [Cloud node](/overview/tools/cloud-node). | | Your applications | Anywhere | You | SDK, REST or MQTT clients, MCP agents, and business systems. | ### Where workflow triggers run Workflows mix cloud and edge nodes in one graph ([node reference](/overview/features/workflow-nodes)). The trigger decides where a run starts: | Trigger | Runs on | | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `webhook`, `schedule`, `event`, `email`, `mission` | Cloud | | `mqtt` | Cloud. On the edge when the workflow is edge-targeted ([details](/feature-reference/workflows/mqtt-trigger)). | | `manual` | Cloud. On the edge when the workflow is marked to run on the edge. | | `camera_frame`, `audio_track`, `zenoh` | Edge only. Raw frames and audio are processed locally and never sent to the cloud. | | `alert` | Edge, according to the node reference. | ## Data flows | Flow | Path | Transport | Leaves the site? | | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **Control** (joint targets, navigation goals, controller commands) | App, workflow or controller → MQTT broker → driver | MQTT over TLS. Some REST calls are relayed to the edge by the backend over MQTT. | Yes. Commands to a twin pass through the cloud broker. | | **Telemetry** (joint states, position, events, edge health) | Driver → broker → backend and browsers | MQTT over TLS. Edge health heartbeat about every 5 s. Host facts over REST about every 30 s. | Yes | | **Live video** | Driver → media service (SFU) → browser or SDK consumer | WebRTC. Signaling over MQTT. TURN relay over TLS on 443 by default. | Yes, while someone is viewing | | **Edge inference** | Camera → worker on the same node, over the local Zenoh bus | Local only | Only detections, events and alerts leave | | **Recordings** | Edge buffers locally, then uploads to Cyberwave storage. Playback uses signed URLs. | HTTPS | Yes | | **Model weights** | Cyberwave storage (signed URL) → upstream URL from the catalog entry → runtime-managed download, tried in that order. The result is cached in `~/.cyberwave/models/`. | HTTPS | Inbound only. Pre-staging from USB is supported ([model cache](/feature-reference/workflows/workers/model-cache)). | | **Container images** | Docker Hub (`cyberwaveos/*`) → edge node | HTTPS | Inbound only | Recording is on by default for every twin, according to [Replay and historical data](/overview/features/replay-and-historical-data). This includes camera video. Check this against the customer's data-handling requirements before you connect cameras. ## Deployment options | Option | Status today | Notes | | ------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SaaS** (multi-tenant, `cyberwave.com`) | Available | Everything else in these docs assumes SaaS. | | **Self-hosted** | A package exists. Contact Cyberwave. | See below. | | **Dedicated / single-tenant managed cloud** | Not documented | Ask Cyberwave. | | **Air-gapped** | Not available as a packaged option | Some parts work offline, such as pre-staged model weights and snapshot import. Container images still come from Docker Hub, and no offline image bundle is documented. | ### Self-hosted: what exists Cyberwave has a self-hosted package, referred to as Cyberwave Enterprise. It is a Docker Compose stack for a single Ubuntu Server 24.04 host with Docker 24+. Today it works like this: * **Images.** Pulled from a private Docker Hub repository, with a read-only pull token issued by Cyberwave. * **Catalog.** Either synced from the production catalog, which needs internet access and a separate token from Cyberwave, or imported from a snapshot bundle that Cyberwave provides. * **Updates.** Pull newer images and restart the stack. An export command snapshots the database and media first. * **Pointing clients at it.** SDK, CLI, Edge Core and cloud nodes read `CYBERWAVE_BASE_URL` and `CYBERWAVE_MQTT_HOST`, so they can target the self-hosted server instead of `api.cyberwave.com` and `mqtt.cyberwave.com`. The self-hosted package is not production-hardened as documented. The reference setup serves the UI, API and MQTT without TLS. It does not document admin bootstrap or how to restrict sign-up. It has no HA, sizing, backup/restore or rollback procedure beyond the snapshot export. Plan TLS termination and access control with Cyberwave before you expose it on a customer network. Contact [info@cyberwave.com](mailto:info@cyberwave.com). ### Not available or not documented yet Customers' IT teams often ask about the items below. Each one was checked against the docs and the public repositories. Don't promise anything here without written confirmation from Cyberwave. | Topic | Status | | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | SSO (SAML, OIDC) | Not documented. Authentication is by account login and [API tokens](/feature-reference/api-tokens). | | Compliance certifications (SOC 2, ISO 27001, others) | Not documented | | Data residency and hosting region | Not documented | | SLA and support tiers | Not documented. A public status page exists at [status.cyberwave.com](https://status.cyberwave.com). | | Built-in OPC UA, Modbus or VDA5050 drivers | Not available. See [PLC, MES and WMS](/enterprise/integration-surfaces#plc-mes-and-wms). | | HTTP(S) proxy support for edge nodes | Not documented. See [Network and firewall](/enterprise/network-and-firewall). | | Audit log | Not documented. Revoked tokens stay listed for audit ([API tokens](/feature-reference/api-tokens)). | ## Evaluation checklist Work through this list with the customer's IT and OT teams before you commit to a design. Get the egress allowlist approved for each component: edge, operator browser, cloud node, and developer machines. Check that TCP 8883 and TLS on 443 are allowed from the cell network. [Network and firewall requirements](/enterprise/network-and-firewall) Choose one workspace per customer or per site, and decide who owns the service tokens. [API tokens](/feature-reference/api-tokens) · [Access control](/feature-reference/access-control) · [Slugs](/feature-reference/concepts/slug-system) For each robot model, confirm whether an official driver exists or you will write one. [Custom hardware](/overview/connecting-hardware/custom-hardware) · [Writing compatible drivers](/feature-reference/edge/drivers/writing-compatible-drivers) Run a scripted install on one golden device. Pin the Edge Core version and decide how updates roll out. [Fleet provisioning](/enterprise/fleet-provisioning) Pick the surface for each system: REST, MQTT, workflow webhooks, MCP, or a custom driver. [Integration surfaces](/enterprise/integration-surfaces) Decide who watches alerts and edge status, and how alerts reach the on-call team. [Alerts](/feature-reference/edge/drivers/alerts) Get written answers from Cyberwave for every item in "Not available or not documented yet" that the customer requires. ## Next steps Every host, port and protocol, per component. Install edge nodes headlessly, then name, monitor and update them. REST, MQTT, webhooks, MCP, ROS 2 and more, with auth for each. The general platform architecture and its local data bus. # Access control Source: https://docs.cyberwave.com/feature-reference/access-control Manage team permissions and project sharing in Cyberwave ## Overview Access control in Cyberwave enables you to securely manage who can view, edit, and administer your data. With flexible permission models and sharing options, you can collaborate effectively with your team while maintaining security and control over your data. **Key Capabilities:** * **Role-based access control** with Viewer, Editor, and Admin permissions * **Project-level sharing** with specific team members * **Public link sharing** for demos and external collaboration * **Organization and workspace membership** management *** ## Access Control and Sharing ### Project Sharing Projects can be shared with specific users or made publicly accessible through links. #### Role-Based Access Share projects with team members using three permission levels: | Role | Permissions | | ---------- | -------------------------------------------------------------- | | **Viewer** | View project, environments, and simulations (read-only) | | **Editor** | Create and modify environments, twins, and datasets | | **Admin** | Full control including project settings, sharing, and deletion | **How to Share:** 1. Navigate to your project settings. 2. Click **Share**. 3. Add users by email. 4. Assign appropriate role (Viewer, Editor, or Admin). 5. Send invitation. #### Public Link Sharing Create shareable links for broader access without requiring authentication: **Link Types:** * **Public Viewer Link:** Anyone with the link can view the project (read-only). * **Public Editor Link:** Anyone with the link can edit the project. **Use Cases:** * Share demos with stakeholders * Collaborate with external partners * Create public showcases of your work Public links grant access to anyone who has the link. Use public editor links cautiously and only for trusted collaborators. *** ## Team Management ### Adding Team Members #### To Organization: 1. Navigate to **Organization Settings** -> **Organization Members**. 2. Click **Add Member**. 3. Enter email address and set organization role. 4. Send invitation. #### To Workspace: **Option 1: Add Existing Organization Member** 1. Navigate to **Workspace Settings** -> **Team Members**. 2. Click **Add User**. 3. Select from existing organization members. 4. Click **Add User**. **Option 2: Add External User** 1. Navigate to **Workspace Settings** -> **Team Members**. 2. Click **Add Member**. 3. Enter external user's email. 4. User will be added to both organization and workspace. When adding external users to a workspace, they automatically become members of your organization as well. This ensures proper billing and access control. *** ## Roles and visibility This page summarizes how **workspace roles** and **resource visibility** combine to determine who can see and manage folders, environments, and related resources. ### Workspace Roles (ACL) | Role | Typical access level | | ----------- | ----------------------------------------------------------------- | | `guest` | No access | | `member` | Workspace participant without automatic read on private resources | | `reader` | Read access to workspace resources | | `developer` | Read + limited write (resource-dependent) | | `writer` | Read + write | | `admin` | Read + write + access management | | `owner` | Full control | ### Visibility Levels | Visibility | Who can see the resource | | ----------- | -------------------------------------------------------------- | | `private` | Owner + users with qualifying workspace role or explicit share | | `workspace` | Active members of the resource workspace | | `project` | Members with access to the project scope | | `org` | Members of the organization | | `public` | Anyone (publicly visible) | | `link` | Anyone with a valid share link | ### Resolution Notes > Access evaluation is role- and visibility-aware. * Workspace role baselines and explicit shares can both grant access. * Reader-level workspace members should be able to list workspace folders and environments they can read. * Developer workspace role can update allowed environment content, but cannot move or delete environments. # API tokens Source: https://docs.cyberwave.com/feature-reference/api-tokens Create tokens for programmatic access, scope them to the workspaces they need, and use service tokens for automation that outlives a person ## Overview An API token authenticates the SDK, the CLI, and anything else that calls Cyberwave programmatically. A token is scoped to the workspaces you choose. It can act in those workspaces and no others, and the scope can be changed after the token is created without re-issuing it. ## Where to create one Your personal tokens. Lists every token you own or administer, and creates user tokens. Tokens that can act in that workspace, including **service tokens**. The workspace you are viewing is always part of the scope. Service tokens are created from workspace settings because they belong to the workspace rather than to you: they hold a role of their own, keep working after you leave, and the workspace's admins can manage them. They still appear under **Profile → Access** if you own or administer them. *** ## Token types Acts as you, narrowed to its workspace scope. It stops working if your account is removed — use it for scripts you run yourself. Acts with its own role rather than yours, so it keeps working after you leave the workspace. Use it for anything long-lived: CI, an edge deployment, a scheduled job. ### Choosing a role for a service token A service token carries a role you pick — Reader, Developer, Writer or Admin. That role is a ceiling: the token can never do more than it allows, **including on objects the token itself created**. Lowering it takes effect immediately. You cannot give a token a role above your own, and you must be an admin of every workspace you scope a **service** token to. A plain user token only needs membership — it acts as you and can never exceed your own access. *** ## Scoping a token Select one or more workspaces when you create the token. Creating from a workspace's own settings locks that workspace into the scope; you can still add others. To change the scope later, use **Edit scope** on the token's row. Removing a workspace takes effect immediately. Adding one requires membership there for a user token, or admin for a service token. Creating a new workspace does not extend any existing token to it. A token's reach only grows when you explicitly add a workspace to its scope. *** ## Naming a workspace on every request Requests say which workspace they act in. A token scoped to exactly one workspace resolves on its own, so nothing changes for single-workspace tokens. With a token scoped to several, a request that does not name one — and cannot infer it from the object it references — is rejected with `400 workspace_required`, listing the workspaces the token holds. Set the workspace once on the client rather than per call: ```python theme={null} from cyberwave import Cyberwave client = Cyberwave( api_key="cw_...", workspace_id="0f6c…", # or set CYBERWAVE_WORKSPACE_ID ) ``` The CLI uses the workspace you logged in with. The web app uses the workspace selected in the UI. *** ## Revoking A token can reach further than the workspace you are looking at. The workspace Tokens tab marks those rows, and warns before you revoke one — revoking removes its access everywhere, not just here. Revoking a token stops it authenticating immediately. For a service token it also deactivates the token's identity, so nothing is left holding permissions. Revoked tokens stay listed for audit; they are never silently deleted. Workspace admins can see and revoke tokens scoped into their workspaces, even ones they did not create — so automation stays manageable after its author leaves. The token's secret is hidden from anyone but its owner. # Architecture Source: https://docs.cyberwave.com/feature-reference/architecture/architecture Dive deep into the architecture of building with Cyberwave ## Overview Cyberwave is a **platform infrastructure for physical AI**. It connects robots, sensors, and actuators to their digital twins and provides a **unified API and SDK** to standardise integration across different hardware. It enables a digital-first workflow for building, testing, and deploying physical AI systems, streamlining delivery from cloud to edge and cutting the path from prototype to production. ## System Architecture | Layer | Description | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Your Applications** | Your Python scripts, SDK integrations, MCP agents, and custom automation code. **Runs anywhere**: local laptop, cloud server, or even on the edge device itself. Communicates with Cyberwave Cloud via the REST API and Python SDK. | | **Cyberwave Cloud** | Digital twins, API, workflow orchestration, model training and deployment, observability dashboard | | **Cyberwave Edge** | The Cyberwave runtime stack installed on your edge compute (Raspberry Pi, Jetson, any Linux machine). Contains the Edge Core and hardware-specific drivers that bridge Cyberwave to the physical robot. | | **Robot Hardware** | Sensors, actuators, motor controllers, microcontrollers, and power systems | ```mermaid theme={null} graph TD subgraph app["Your Applications"] sdk["Python SDK"] mcp["MCP Agents"] custom["Custom Scripts / CI"] end subgraph cloud["Cyberwave Cloud"] dt["Digital Twins"] api["API"] models["Models & Workflows"] end subgraph edge["Cyberwave Edge"] core["Cyberwave Edge Core"] drivers["Cyberwave Hardware Drivers"] end subgraph hw["Robot Hardware"] sensors["Sensors"] actuators["Actuators"] mcu["Microcontroller"] end app <-- "REST API / MQTT" --> cloud cloud <-- "MQTT / REST" --> edge edge <-- "Serial / USB / ROS Topics" --> hw ``` ## System Components ### Your Applications This is where **your code** lives. Whether it's a Python script on your laptop, an MCP-powered AI agent in your IDE, a backend service in the cloud, or automation in a CI pipeline, your application connects to Cyberwave Cloud via the REST API and Python SDK. The primary programmatic interface. Create twins, control joints, capture frames, trigger workflows, and manage infrastructure. Runs on any machine with Python 3.10+: your laptop, a cloud VM, a Jupyter notebook, or even the edge device itself. AI agents (Claude, GPT, Gemini, Cursor) that discover and call Cyberwave tools autonomously through the Model Context Protocol. They connect to the hosted MCP server or a self-hosted instance. Direct REST API calls, webhook handlers, CI/CD pipelines, or any custom code that interacts with the Cyberwave API. No SDK required; any language that can make HTTP requests works. Your application code is **location-independent**. It does not need to run on the same device as the edge runtime or the robot. The SDK communicates with Cyberwave Cloud over HTTPS and MQTT over TLS (port 8883), so it works from anywhere with outbound internet access. ### Cyberwave Cloud The cloud layer is the central control plane of the Cyberwave platform. It provides the backend services and compute infrastructure required to manage robots, digital twins, simulations, and AI models at scale. Your applications and the edge runtime both connect to the cloud. The core cloud service layer, handling identity and access management, policy enforcement, orchestration, digital twin registry, and developer interfaces for visualization, workflow management, and administrative control. Cloud-scale simulation infrastructure including physics-based simulation and log replay. These services support reproducible testing and sim-to-real continuity. Model lifecycle pipelines covering training, evaluation, validation, governance, and publishing of deployable learning artifacts. Models trained here can be deployed directly to edge nodes. ### Cyberwave Edge An **edge node** is a physical compute unit deployed at the **periphery of the Cyberwave platform** (e.g., industrial PC, embedded computer, Raspberry Pi, or similar hardware), typically co-located with one or more robots or connected devices. Edge nodes operate under strict latency, bandwidth, reliability, safety, and security constraints and are designed to function even under degraded or intermittent connectivity. For clarity: **edge node** refers to the physical host, and **edge runtime** refers to the software system executing on it. The edge runtime is a hybrid system: * **Edge Core**: a central host-level service running on the node OS. It handles identity, authentication, device registration, and coordination with the cloud backend. * **Runtime Services**: a set of isolated Docker containers running modular, replaceable, and vendor-isolated services (e.g., hardware drivers, inference engines, data pipelines). This separation ensures a stable, trusted control plane while enabling flexible, swappable runtime services. ### Robot Hardware The physical layer consists of the robot's hardware components: * **Sensors**: cameras, LiDAR, IMUs, encoders, and other perception devices that stream data to the edge runtime. * **Actuators**: motors, servos, grippers, and other effectors that receive commands from the edge runtime. * **Microcontroller**: the low-level controller (e.g., Arduino, STM32) that interfaces directly with sensors and actuators over serial, I2C, SPI, or CAN bus. ## Communication Protocols ### Applications ↔ Cyberwave Cloud: REST API / MQTT Your application code communicates with the Cyberwave cloud over **HTTPS REST APIs** for all CRUD operations (twins, environments, workflows, assets, alerts) and **MQTT over TLS** (`mqtt.cyberwave.com`, port 8883) for real-time state updates and commands. The Python SDK and MCP server both use these protocols under the hood. Live camera feeds use **WebRTC** instead, described in [Video Streaming](#video-streaming-webrtc) below. ### Cyberwave Cloud ↔ Edge: MQTT / REST The edge runtime maintains a persistent connection to the Cyberwave cloud via **MQTT** for real-time bidirectional messaging (telemetry, commands, state sync) and **REST APIs** for request-response operations (registration, pairing, config). This hybrid approach ensures low-latency streaming alongside reliable transactional operations. ### Edge ↔ Robot Hardware: Serial / USB / ROS Topics The edge runtime communicates with the physical robot over local interfaces: **Serial** (UART), **USB**, or **ROS Topics**, depending on the robot's hardware architecture. The **Cyberwave hardware driver** abstracts these transport differences, exposing a unified interface to the rest of the edge stack. ## Video Streaming (WebRTC) Live camera feeds (teleoperation, monitoring, cameras panel) stream from the edge to the browser over **WebRTC**, while control commands and telemetry continue to travel over MQTT. The edge publishes each stream to Cyberwave's **media service** (a WebRTC SFU), which forwards it to browsers and SDK consumers. When the edge cannot reach the media service directly, for example behind a restrictive NAT or corporate firewall, media goes through Cyberwave's **TURN relay**, which the SDK reaches over TLS on port 443 (`tls.turn.cyberwave.com`). Signaling (exchanging connection offers/answers) happens over the same MQTT connection the edge already uses, so it doesn't require any additional inbound ports. #### Connectivity requirements Because WebRTC and TURN negotiate connections outbound, you typically don't need to open any **inbound** ports on the edge network. What you do need is **outbound** access from the edge network (and from the operator's browser/network) to the following: | Purpose | Protocol / Ports | Destination | | ------------------------------------------------------- | --------------------------------- | ------------------------ | | TURN relay over TLS (default) | TCP `443` | `tls.turn.cyberwave.com` | | STUN | UDP `3478` | `turn.cyberwave.com` | | TURN over UDP (opt-in with `CYBERWAVE_WEBRTC_TURN_URL`) | UDP/TCP `3478`, UDP `49152–65535` | `turn.cyberwave.com` | The default relay uses TCP 443 because many corporate and industrial networks block port 3478 and outbound UDP on high ports. If your network also inspects or blocks TLS to `tls.turn.cyberwave.com`, video cannot establish a media path even though MQTT control still works. See [Network and firewall requirements](/enterprise/network-and-firewall). ## Local Data Bus (Zenoh) Alongside MQTT (used for edge ↔ cloud communication), the edge runtime uses **Zenoh** as a local, low-latency publish/subscribe data bus. Zenoh carries high-frequency traffic between the Edge Core and hardware drivers/workers running on the same edge node (sensor readings, joint states, inference outputs) without adding load to the cloud link. Only the data you explicitly forward is bridged out to Cyberwave Cloud over the existing MQTT connection. Zenoh traffic stays on your local network. It's not used for edge ↔ cloud communication, and it doesn't require any internet access. #### Connectivity requirements | Mode | Protocol / Port | When it applies | | -------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------- | | Peer-to-peer discovery (default) | UDP multicast, local subnet only | Single edge node, or multiple drivers/workers on the same host — no firewall changes needed | | Zenoh router (optional) | TCP `7447` | Only if you run drivers across **multiple hosts** on the same site and enable router mode to bridge them | For a single-node deployment (the common case), Zenoh requires no firewall configuration at all. If you spread drivers across several machines on the same local network, allow TCP `7447` between those hosts. *** ## Next Steps Learn the core platform concepts Understand the organisational hierarchy # Data model Source: https://docs.cyberwave.com/feature-reference/architecture/core-data-hierarchy Understanding Cyberwave's organizational structure and data model ## Overview Cyberwave organises resources in a simple top-down hierarchy: **Organization → Workspace → Environment**. Each level scopes access, permissions, and resource isolation so teams can collaborate without stepping on each other. ## Data Hierarchy | Level | Contains | Description | | ---------------- | ------------------------------- | ------------------------------------------------------------------- | | **Organization** | Workspaces | Your company or team, the top-level account that owns all resources | | **Workspace** | Environments, Workflows | A shared space for a team or department to collaborate | | **Environment** | Digital Twins, Datasets, Assets | A 3D space that mirrors your real-world robot setup | ```mermaid theme={null} graph TD A[Organization] --> B[Workspace] B --> C[Environment] B --> D[Workflows] C --> E[Digital Twins] C --> F[Datasets] C --> G[Assets] style A fill:#d0f0fa,stroke:#7ec8e3,color:#333 style B fill:#e0f7fa,stroke:#80deea,color:#333 style C fill:#f3e5f5,stroke:#ce93d8,color:#333 style D fill:#fff4e6,stroke:#ffb74d,color:#333 style E fill:#e8f5e9,stroke:#81c784,color:#333 style F fill:#e8f5e9,stroke:#81c784,color:#333 style G fill:#e8f5e9,stroke:#81c784,color:#333 ``` *** ### Organization The top-level entity representing your company or team. All users, workspaces, and billing are managed here. * Centralised team and member management * Billing, subscriptions, and usage tracking * Organization-wide settings and policies *** ### Workspace A workspace groups related environments and workflows under a shared context, typically scoped to a team, department, or deployment stage. * Multiple workspaces per organization * Workspace-level member access and permissions * Invite external collaborators by email Create separate workspaces for different teams (e.g., "Research", "Production", "QA") or stages (e.g., "Development", "Staging"). Use **Folders** to organise related environments within a workspace. Folders are an optional grouping mechanism; they help keep things tidy as your workspace grows. *** ### Environment An environment is a 3D virtual space that mirrors your real-world robot setup. It's where your digital twins live, sensors stream data, and controllers send commands, all in real time. * Multiple environments per workspace * **Edit Mode** for designing and configuring the space * **Live Mode** for real-time operation and data streaming **An environment contains:** Virtual replicas of physical robots, mirroring structure, joints, sensors, and behavior in real time. Recorded operations and telemetry data collected during robot demonstrations. 3D objects, sensors, cameras, and other elements placed in the environment. Physics-enabled test scenarios for reproducible testing and validation. *** ### Workflows Workflows exist at the workspace level and can orchestrate operations across multiple environments. * Visual node-based editor for building automation sequences * Trigger-based execution, manual, scheduled, or event-driven * Cross-environment automation capabilities *** ## Example ``` Organization: RoboTech Industries └── Workspace: Research & Development ├── Environments: │ ├── "Lab Setup A" │ ├── "Lab Setup B" │ └── "Test Track" └── Workflows: ├── "Data Collection Pipeline" └── "Model Training Workflow" ``` *** ## Next Steps Understand the system architecture Learn core platform concepts Get started with your first environment # Glossary Source: https://docs.cyberwave.com/feature-reference/architecture/key-concepts A–Z reference for every Cyberwave term you'll encounter in the docs, dashboard, and SDK. This page is a quick reference for the vocabulary used throughout Cyberwave. For deeper explanations, follow the links to the relevant feature pages. *** ### API Token Cyberwave uses **API tokens** to authenticate requests for the [Python SDK](/overview/tools/python-sdk), REST API calls, and MQTT connections. Each token is scoped to a specific workspace. See [Authentication](/feature-reference/setup-cyberwave) for setup. ```bash theme={null} CYBERWAVE_API_KEY=cw_live_xxxxxxxxxxxxxxxxxxxx CYBERWAVE_BASE_URL=https://api.cyberwave.com CYBERWAVE_WORKSPACE_ID=workspace_xxxxxxxxxxxxxxxxxxxx ``` Keep your API keys secure. Never commit them to version control or share them publicly. *** ### Asset / Asset Catalog The **Asset Catalog** is Cyberwave's library of pre-configured robot assets. Each asset includes a unique registry ID (e.g. `the-robot-studio/so101`), a URDF describing joints and links, a 3D model, and metadata about capabilities. Asset types include robot arms, mobile robots, quadrupeds, and drones. See [Catalog](/feature-reference/catalog). *** ### Controller Policy A **controller policy** determines how a robot acts. Cyberwave supports manual control (dashboard or SDK), teleoperation (leader → follower), remote operation (dashboard → follower only), and AI models (trained policies that execute autonomously). *** ### Dataset A **dataset** is a collection of recorded robot operations used for training AI models. Each dataset contains multiple **episodes** with joint positions, camera feeds, and timing data. *** ### Digital Twin A **digital twin** is a virtual replica of a physical robot that mirrors its behavior, capabilities, and state in real time. It includes an accurate 3D model, physics simulation, virtual sensors matching the physical setup, and bidirectional sync with the physical robot. See [Work with digital twins](/feature-reference/digital-twins). *** ### Driver A **driver** is a Docker container that translates between a piece of hardware's native interface (serial, USB, ROS, gRPC, Modbus, etc.) and Cyberwave's MQTT layer. Drivers are managed by the Edge Core and can be installed from the catalog or written custom. See [Drivers Overview](/feature-reference/edge/drivers/overview). *** ### Edge Core The **Edge Core** is the central host-level service of the Cyberwave edge runtime. It handles identity, authentication, device registration, driver orchestration, and coordination with Cyberwave Cloud over MQTT. See [Edge Overview](/feature-reference/edge/overview). *** ### Edge Node An **edge node** is a physical compute unit deployed at the periphery of the platform (industrial PC, embedded computer, Raspberry Pi, Jetson) — typically co-located with one or more robots. Edge nodes run under strict latency, bandwidth, and reliability constraints and are designed to operate even under degraded connectivity. *** ### Edge Worker An **Edge Worker** is a containerised module — usually an AI model or data pipeline — that runs alongside the Edge Core for low-latency, on-device inference. Frames and telemetry never have to leave the device. See [Edge Workers](/feature-reference/edge/drivers/edge-workers). *** ### Environment An **environment** is a 3D space where your digital twins exist and interact. It can represent a physical facility (warehouse, lab, outdoor site), a testing scenario, or a pure simulation environment. Environments support **Edit Mode** (designing and configuring) and **Live Mode** (real-time operation and monitoring). See [Environment editor](/feature-reference/environment-editor). *** ### Episode An **episode** is a single recording of a robot completing a task from start to finish. Record 10–15 demonstrations of the same task with slight variations for better model generalisation. *** ### AI Model **AI models** are models registered in your workspace that process inputs (video, images, audio, text, robot actions) and integrate with workflows. Cyberwave provides the full pipeline: collect data → create datasets → train → deploy as a controller policy → execute autonomously. See [Model catalog](/feature-reference/ml-models). *** ### Operator Alerts Cyberwave can raise **alerts** when a robot is missing required calibration, or when a controller is attached, removed, or swapped, so operators complete setup in the right order. The UI may disable actions while these conditions apply, to reduce the risk of unsafe behaviour. See [Driver Alerts](/feature-reference/edge/drivers/alerts). *** ### Organization The **organization** is the top-level account that owns all workspaces, environments, and resources for your company or team. *** ### Remote Operation **Remote operation** controls a follower arm directly from the Cyberwave dashboard — no leader arm required. Useful for testing, calibration, and manual joint control without a physical leader. See [Live Teleoperation](/feature-reference/environment-editor/teleoperation). *** ### Teleoperation **Teleoperation** uses a physical leader arm (or other input device) to control a follower in real time. Ideal for collecting demonstration data for training. See [Live Teleoperation](/feature-reference/environment-editor/teleoperation). *** ### Workflow **Workflows** are automated sequences of robot operations built through visual orchestration. Connect nodes to compose complex behaviours without writing procedural code. Workflows can be triggered manually, on a schedule, by events, by webhook, or by camera frames (on the edge). See [Workflows](/feature-reference/workflows). *** ### Workspace A **workspace** is your team's container for environments, workflows, and resources. It provides centralised authentication, team collaboration, permissions, resource sharing across environments, and billing. Use separate workspaces for different teams or deployment stages (e.g., "Development", "Testing", "Production"). *** ## Related Reference How the cloud, edge, and hardware layers fit together. Organization → Workspace → Environment hierarchy. # Arm commands Source: https://docs.cyberwave.com/feature-reference/arm-commands Standard end-effector, gripper, and base commands for robotic arms Robotic-arm twins expose a standard command vocabulary via `twin.commands` (and grouped handles like `twin.gripper`). Availability depends on the robot. | Command | Args | Description | | ---------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------- | | `ee_move` | `forward`, `up`, `left` (m), `frame` (`tool`\|`base`) | Translate the end-effector. | | `ee_rotate_left` / `ee_rotate_right` | `angle` (rad) | Yaw the end-effector. | | `ee_rotate_up` / `ee_rotate_down` | `angle` (rad) | Pitch the end-effector. | | `base_rotate_left` / `base_rotate_right` | `angle` (rad) | Rotate the base joint. | | `grip` | `force` (0–1) | Close the gripper. Also `twin.gripper.grip(force)`. | | `release` | — | Open the gripper. Also `twin.gripper.release()`. | | `home` | — | Return to the home pose. | | `ee_pose` | `pose` — 6-element array `[x, y, z, roll, pitch, yaw]` (m, rad) | Move the end-effector to an absolute pose. | ```python theme={null} twin.commands.ee_move(forward=0.05) twin.commands.ee_pose(pose=[0.3, 0.0, 0.4, 0.0, 1.57, 0.0]) twin.commands.grip(force=1.0) twin.commands.release() twin.commands.home() ``` Dual-arm robots (one twin, two end-effectors) expose the same commands prefixed per arm — `left_ee_move`, `right_grip`, `left_ee_pose`, … — plus a conjunct `home` that returns both arms. # Asset schema variants Source: https://docs.cyberwave.com/feature-reference/asset-schema-variants Carry an alternate schema such as ``simplified_mesh`` alongside an asset's canonical universal schema An **asset schema variant** is an optional, per-asset alternate JSON schema that lives alongside the canonical `Asset.universal_schema`. The first supported kind is `simplified_mesh`, intended for vectorized GPU training where lighter-weight collision/visual geometry matters. V1 supports **manual JSON upload only** — automatic mesh simplification is intentionally out of scope. ## Why variants instead of overwriting? The canonical universal schema is owned by the URDF/asset pipeline and is what every other Cyberwave subsystem (twins, environments, MQTT, the editor) snapshots from. Variants let downstream consumers — e.g. a vectorized training cluster — request a different representation for the same asset without breaking the canonical one. Variants are additive and never silently substitute the canonical schema. ## Lifecycle 1. From the asset detail page → **Files** tab → **Asset schema variants** section. 2. Click **Upload JSON** on the *Simplified mesh* card and pick a JSON file. The body must be a JSON object; the file is parsed once on upload. 3. The variant card now shows **Available** with computed metadata (link / joint counts, hash). 4. Click **Download JSON** on either card at any time to get the schema as a file. 5. **Replace JSON** overwrites the same variant; **Remove** deletes it entirely. The canonical universal schema is never touched. ## API surface * `GET /api/v1/assets/{uuid}/schemas` — list available schemas, including a virtual `base` entry when the asset has one. * `GET /api/v1/assets/{uuid}/schemas/{kind}` — metadata for one variant. * `PUT /api/v1/assets/{uuid}/schemas/{kind}` — create or replace a variant. V1 accepts `kind=simplified_mesh` only; `base` is reserved for the canonical schema and rejected. * `DELETE /api/v1/assets/{uuid}/schemas/{kind}` — delete a DB-backed variant. * `GET /api/v1/assets/{uuid}/schema.json?kind=base|simplified_mesh` (default `base`) — download the chosen schema as JSON. ## .cbw export and import `.cbw` packages now include any schema variants under `schemas/{kind}.json` plus a `schema_variants` entry in the manifest. Importing a `.cbw` restores the variants without touching the imported asset's canonical universal schema. ## Limits and roadmap * V1 is upload-only. Automatic mesh simplification will land in a follow-up. * Today only one variant kind is recognised (`simplified_mesh`). New kinds are added by extending `AssetSchemaVariantKind` in the backend; older clients will continue to ignore unknown kinds in `.cbw` packages. # Catalog Source: https://docs.cyberwave.com/feature-reference/catalog Browse pre-built robot assets and upload your own to create digital twins ## What is the Asset Catalog? The Asset Catalog is Cyberwave's library of pre-configured robot assets. Each asset includes a 3D model, kinematic definition (URDF), and metadata that lets you create digital twins with a single line of code. Assets in the catalog are identified by a **registry ID** in the format `vendor/model`, such as `the-robot-studio/so101` or `unitree/go2`. *** ## Browsing and adding assets The catalog shows one row of your matching assets above public assets. **All** also includes workspace and privately shared assets in **Shared with you**, with a first-row preview and **Show more shared assets**. Empty personal and shared sections are hidden. Use **Yours** beside sorting to browse all your assets. Desktop filters sit on the left; **Filters** reveals them on smaller screens. Selected filters remain visible above results and can be removed individually. **Add asset** combines file upload and image/prompt generation. Choose files with the keyboard or pointer. At the Access step, **Create workspace** opens a modal and selects the new workspace without losing your file, prompt, or asset details. On an asset page, editors can use the right-hand onboarding checklist to configure missing capabilities and controllers. These shortcuts disappear once the corresponding tabs are available. Viewers see completed attributes only. Editors see unfinished checks first; expand **Reviewed** to inspect or update completed and not-applicable assessments. Empty filtered results offer **Clear search and filters** to restore results without changing the All/Yours/Public scope. ## Using Catalog Assets ### Create a Twin from an Asset Use the Python SDK to create a digital twin from any catalog asset: ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="your_api_key") robot = cw.twin("unitree/go2") ``` The `cw.twin()` function handles everything: * Finds the asset in the catalog * Creates (or retrieves) a digital twin in your environment * Returns an appropriate Twin class based on the asset's capabilities ### Search the Catalog ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="your_api_key") for asset in cw.assets.search("unitree"): print(f"{asset.registry_id}: {asset.name}") ``` ### Browse the Web Interface Browse assets at [cyberwave.com/catalog](https://cyberwave.com/catalog): * Browse hardware categories, including arms, rovers, quadrupeds, and drones * Combine vendor, sensor, and capability filters; use **Filters** on smaller screens * Search by manufacturer or model name * View 3D previews and specifications * Choose **Add asset** to upload a robot package, model, or scan, or generate a mesh from an image or prompt * Follow the same Source → Details → Access steps, with private visibility by default *** ## Asset Capabilities Assets in the catalog have different capabilities based on their type: Joint control, inverse kinematics, gripper operations Position control, rotation, navigation Leg joint control, gait patterns, camera streaming Takeoff, landing, hover, flight control The SDK automatically returns the right Twin class based on capabilities: ```python theme={null} arm = cw.twin("the-robot-studio/so101") arm.joints.set("shoulder_pan", 45, degrees=True) camera = cw.twin("cyberwave/standard-cam") await camera.stream_video_background() dog = cw.twin("unitree/go2") ``` *** ## Asset Structure Each catalog asset contains: | Component | Description | | ---------------- | --------------------------------------- | | **Registry ID** | Unique identifier (`vendor/model`) | | **URDF File** | Robot description with joints and links | | **3D Model** | GLB mesh for visualization | | **Metadata** | Category, manufacturer, version, tags | | **Capabilities** | Sensors, grippers, flight, etc. | *** ## Upload a New Asset ### What is a URDF? URDF (**Unified Robot Description Format**) is the standard XML format used in ROS to describe a robot's links, joints, visuals, and collisions. References: * [ROS 2 URDF documentation](https://docs.ros.org/en/rolling/Tutorials/Intermediate/URDF/URDF-Main.html) * [ROS Wiki: URDF](https://wiki.ros.org/urdf) * [urdfdom (URDF parser library)](https://github.com/ros/urdfdom) ### Prepare Your ZIP File Create a folder that contains one main `.urdf` file and every file it references (meshes, textures, materials), then zip the folder. ```text theme={null} my-robot/ urdf/ robot.urdf meshes/ base_link.stl arm_collision.stl arm_visual.obj textures/ arm_albedo.png ``` Use relative paths inside the URDF that match your ZIP structure. If the URDF references `meshes/arm_visual.obj`, that file must exist at that path in the ZIP. ZIP uploads can be up to 512 MB, enough for large full-mesh assets like humanoid robots. ### Upload from the UI For a step-by-step walkthrough of the dashboard upload wizard (Source → Details → Access), see [Create an Asset](/feature-reference/create-asset). Sign in to [cyberwave.com](https://cyberwave.com) (or sign up). Navigate to [cyberwave.com/catalog](https://cyberwave.com/catalog) and click **Add asset**. Enter the required fields and upload your URDF ZIP file. * **Main URDF File Path** — if your ZIP has multiple URDF files, set the path (e.g. `urdf/robot.urdf`). Leave empty if there's only one. * **Thumbnail** — optional. Cyberwave can generate one automatically. ### Upload from the API ```bash theme={null} curl -X POST "https://api.cyberwave.com/api/v1/assets/create-with-urdf" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "file_url": "https://example.com/my-robot.zip", "force_name": "my-robot", "main_file_path": "urdf/robot.urdf", "description": "My robot uploaded from URDF ZIP" }' ``` | Field | Description | | ---------------- | ----------------------------------------------------- | | `file_url` | URL to your ZIP file (must be reachable by Cyberwave) | | `force_name` | Name for the asset | | `main_file_path` | Path to the main URDF file inside the ZIP | | `description` | Optional description | | `subfolder` | Optional subfolder within the ZIP | | `branch` | Optional version/branch identifier | ### Upload via Python SDK ```python theme={null} asset = cw.assets.create(name="My Robot", description="Custom robot model") cw.assets.upload_glb(asset.uuid, "path/to/model.glb") ``` # Asset kits Source: https://docs.cyberwave.com/feature-reference/catalog/asset-kits Reuse robots and accessories as a docked assembly In **Catalog**, choose **Create kit**, name the kit, and select its workspace and visibility. Choose a base asset, add accessories, and set each accessory's parent, attachment link, offset in metres, and rotation. Save the kit. Kits appear alongside assets with a **Kit** badge. Their detail pages link to each component and show its usual detail tabs. Purchase and monthly prices total the component prices; an unknown component price leaves the total unavailable. **Use in environment** adds the components together with the saved docking layout. You need access to every component and permission to add twins to the environment. Editing a kit affects future deployments, not existing twins. Kits contain 2–50 individual assets and one base; nested kits are not supported. ```python theme={null} kit = client.assets.create_kit( "Robot with camera", [ {"key": "robot", "asset_uuid": robot_uuid}, {"key": "camera", "asset_uuid": camera_uuid, "parent_key": "robot", "position": [0, 0, 0.25]}, ], workspace_uuid=workspace_uuid, ) twins = client.assets.instantiate_kit(kit["asset"]["uuid"], environment_uuid) ``` List parents before children. Omit the attachment link to use the parent's root. Rotations use quaternions in `[w,x,y,z]` order. Use `client.assets.get_kit(uuid)` and `client.assets.update_kit(...)` to inspect or replace a saved kit. An update preserves the existing description and visibility when those arguments are omitted. # Simulator compatibility Source: https://docs.cyberwave.com/feature-reference/catalog/simulation-support Control which simulators assets and twins can participate in. Every asset stores a default list of simulation backends it supports. Twins created from that asset inherit the asset's defaults and can override them individually. ## How it works 1. **Asset defaults** — Open any asset in the catalog and expand **Simulator compatibility** to enable or disable each backend. This becomes the starting point for all twins created from that asset. 2. **Per-twin overrides** — In the environment editor, select a twin and open the twin panel. The **Simulator compatibility** section (near the Fixed base toggle) lets you override the asset default for that specific twin instance. 3. **Compatibility gate** — When you try to start a remote simulation (e.g. MuJoCo), Cyberwave checks every twin in the environment. If any twin is not marked as compatible with the selected backend, the simulation will not start and the simulator panel will list the incompatible twins. ## Supported backends | Backend | Description | | -------------- | ------------------------------------------------------------------------------------------- | | **Playground** | Built-in browser simulation. Does not require a compatibility check before starting. | | **MuJoCo** | High-fidelity physics simulation. All twins must be compatible for the simulation to start. | ## Changing compatibility * **To fix a blocked MuJoCo simulation:** either enable MuJoCo on the incompatible twin(s) in the twin panel, or update the asset default so future twins are compatible by default. * **To exclude a twin from MuJoCo:** disable MuJoCo on that twin in the twin panel. The twin will remain in the environment for other purposes but will block MuJoCo start until re-enabled. ## Notes ### Prepare missing simulation data Select a robot or procedural object in the environment editor and open **Simulation readiness → Prepare simulation**. Confirm the checks, follow progress there, and review the proposed changes. Estimates require separate acceptance; stop simulation, controllers and training before applying. Shared catalog assets and calibration stay unchanged. A passing MuJoCo check is not proof of real-world accuracy, successful grasping or camera streaming. Missing data and blank camera renders remain visible as blockers. Preparation does not start policy training or publish assets. * New twins always inherit the asset's compatibility list at creation time. Changing the asset default does not retroactively update existing twins. * Playground is not enforced by a server-side gate; it is always available as a local simulation option regardless of twin compatibility settings. # Upload a new asset (URDF ZIP) Source: https://docs.cyberwave.com/feature-reference/catalog/upload-asset How to package and upload a URDF asset from the UI or API ## What is a URDF? URDF (**Unified Robot Description Format**) is the standard XML format used in ROS to describe a robot's links, joints, visuals, and collisions. Useful open-source references: * [ROS 2 URDF documentation](https://docs.ros.org/en/rolling/Tutorials/Intermediate/URDF/URDF-Main.html) * [ROS Wiki: URDF](https://wiki.ros.org/urdf) * [urdfdom (URDF parser library)](https://github.com/ros/urdfdom) *** ## Prepare your ZIP file correctly Before uploading, create a folder that contains: 1. One main `.urdf` file 2. Every file referenced by that URDF (meshes, textures, materials) Then zip that folder. ```text theme={null} my-robot/ urdf/ robot.urdf meshes/ base_link.stl arm_collision.stl arm_visual.obj textures/ arm_albedo.png ``` ### File references inside URDF Your URDF can reference other files, for example: * **STL** files for collision geometry * **OBJ** files for visual geometry / textured visuals * Texture image files used by materials (for example PNG/JPG) Use relative paths that match your ZIP structure. If the URDF references `meshes/arm_visual.obj`, that file must exist in the ZIP. Symbolic links inside the ZIP are supported and resolved automatically. *** ## Upload from the UI 1. Sign in (or sign up) 2. Go to [cyberwave.com/catalog](https://cyberwave.com/catalog) 3. Click **Upload Asset** 4. Fill in required fields and upload your URDF ZIP 5. (Optional) Open **Advanced** for extra fields ### Advanced form fields * **Main URDF File Path** * If your ZIP has only one URDF file, you can leave this empty * If your ZIP has multiple URDF files, set the path (for example `urdf/robot.urdf`) * **Thumbnail** * Optional * If you do not upload one, Cyberwave can generate a thumbnail automatically *** ## Upload from the API (`create-with-urdf`) Use: * `POST /api/v1/assets/create-with-urdf` Example: ```bash theme={null} curl -X POST "https://api.cyberwave.com/api/v1/assets/create-with-urdf" \ -H "Authorization: Bearer $CYBERWAVE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "file_url": "https://example.com/my-robot.zip", "force_name": "my-robot", "main_file_path": "urdf/robot.urdf", "description": "My robot uploaded from URDF ZIP" }' ``` API payload fields: * `file_url`: URL to your ZIP file * `force_name`: Name for the asset * `main_file_path`: Main URDF path in the ZIP * `description` (optional) * `subfolder` (optional) * `branch` (optional) For API uploads, make sure `file_url` is reachable by Cyberwave and points to the final ZIP file. *** ## Set physics properties When Cyberwave processes your URDF ZIP it generates a **universal schema** — the canonical JSON representation of your robot. The schema includes a `physics` object that controls world-level simulation parameters such as gravity, timestep, solver, and default contact surface. There is no physics editor in the UI yet. Use the PATCH API below to configure physics after uploading. ### Physics object structure | Field | Type | Default | Description | | --------------------- | ----------- | ------------------------ | -------------------------------------------------------- | | `gravity` | `{x, y, z}` | `{x: 0, y: 0, z: -9.81}` | World gravity vector | | `timestep` | `float` | `0.001` | Simulation timestep (seconds) | | `solver.type` | `string` | `"quick"` | Solver type: `quick`, `ode`, `bullet`, `dart`, `simbody` | | `solver.iterations` | `int` | `50` | Solver iterations per step | | `contact.mu_static` | `float` | `0.8` | Default static friction | | `contact.mu_dynamic` | `float` | `0.7` | Default dynamic friction | | `contact.restitution` | `float` | `0.1` | Default restitution (bounciness) | | `contact.stiffness` | `float` | `10000.0` | Contact stiffness | | `contact.damping` | `float` | `20.0` | Contact damping | ### Set physics via API Use the universal schema PATCH endpoint: * `PATCH /api/v1/assets/{uuid}/universal-schema` Each call sends a single JSON Pointer operation: ```bash theme={null} curl -X PATCH "https://api.cyberwave.com/api/v1/assets/$ASSET_UUID/universal-schema" \ -H "Authorization: Bearer $CYBERWAVE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "op": "add", "path": "/physics", "value": { "gravity": { "x": 0, "y": 0, "z": -9.81 }, "timestep": 0.001, "solver": { "type": "quick", "iterations": 50 }, "contact": { "mu_static": 0.8, "mu_dynamic": 0.7, "restitution": 0.1 } } }' ``` You can also patch individual sub-fields without overwriting the entire object: ```bash theme={null} curl -X PATCH "https://api.cyberwave.com/api/v1/assets/$ASSET_UUID/universal-schema" \ -H "Authorization: Bearer $CYBERWAVE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "op": "replace", "path": "/physics/gravity", "value": { "x": 0, "y": 0, "z": -3.71 } }' ``` ### Set physics via Python SDK The Python SDK provides convenience methods so you don't need to craft JSON Pointer operations manually. All setter methods use a read-modify-write pattern: omitted fields keep their current values. ```python theme={null} import cyberwave cw = cyberwave.Cyberwave() ``` #### `set_physics` — set multiple physics fields at once ```python theme={null} cw.assets.set_physics( asset_id, gravity={"x": 0, "y": 0, "z": -9.81}, timestep=0.002, solver={"type": "quick", "iterations": 100}, contact={"mu_static": 1.0, "restitution": 0.05}, ) ``` | Parameter | Type | Description | | ---------- | ------- | -------------------------------------- | | `gravity` | `dict` | `{"x", "y", "z"}` vector | | `timestep` | `float` | Simulation timestep (seconds) | | `solver` | `dict` | Solver config (merged with existing) | | `contact` | `dict` | Contact surface (merged with existing) | #### `set_gravity` — shorthand for the gravity vector ```python theme={null} cw.assets.set_gravity(asset_id, z=-3.71) # Mars cw.assets.set_gravity(asset_id, z=0.0) # Zero-g cw.assets.set_gravity(asset_id) # Earth (default) ``` #### `set_physics_solver` — configure the solver ```python theme={null} cw.assets.set_physics_solver( asset_id, solver_type="bullet", iterations=200, ) ``` | Parameter | Type | Description | | --------------- | ------- | ----------------------------------------------------- | | `solver_type` | `str` | `"quick"`, `"ode"`, `"bullet"`, `"dart"`, `"simbody"` | | `iterations` | `int` | Solver iterations per step | | `sor` | `float` | Successive Over-Relaxation (ODE) | | `min_step_size` | `float` | Minimum step size | | `max_step_size` | `float` | Maximum step size | | `tolerance` | `float` | Solver tolerance | #### `set_contact_properties` — tune the default contact surface ```python theme={null} cw.assets.set_contact_properties( asset_id, mu_static=1.0, restitution=0.0, ) ``` | Parameter | Type | Default | Description | | ------------- | ------- | --------- | ----------------- | | `mu_static` | `float` | `0.8` | Static friction | | `mu_dynamic` | `float` | `0.7` | Dynamic friction | | `restitution` | `float` | `0.1` | Bounciness | | `stiffness` | `float` | `10000.0` | Contact stiffness | | `damping` | `float` | `20.0` | Contact damping | #### `get_physics` — read the current physics ```python theme={null} physics = cw.assets.get_physics(asset_id) if physics: print(physics["gravity"]) # {"x": 0, "y": 0, "z": -9.81} print(physics["timestep"]) # 0.001 ``` Returns `None` if no physics have been configured yet. *** ## Universal schema helpers (Python SDK) Beyond physics, the SDK exposes general-purpose methods for reading and writing any part of the universal schema. #### `get_universal_schema` — download the full schema ```python theme={null} schema = cw.assets.get_universal_schema(asset_id) print(schema["links"]) print(schema["extensions"]["cyberwave"]["capabilities"]) ``` #### `get_universal_schema_at_path` — read a specific sub-path ```python theme={null} result = cw.assets.get_universal_schema_at_path(asset_id, "/sensors/0") sensor = result["value"] result = cw.assets.get_universal_schema_at_path(asset_id, "/physics/gravity") gravity = result["value"] ``` #### `patch_universal_schema` — write to any JSON Pointer path ```python theme={null} cw.assets.patch_universal_schema( asset_id, path="/extensions/cyberwave/capabilities/locomotion", value={"mode": "wheeled", "has_wheels": True}, op="add", ) ``` | Parameter | Type | Description | | --------- | ----- | ------------------------------------------------------------- | | `path` | `str` | JSON Pointer (e.g. `"/physics/gravity"`, `"/sensors/0/name"`) | | `value` | `any` | Value to set | | `op` | `str` | `"add"` or `"replace"` (default: `"replace"`) | #### `rebuild_universal_schema` — regenerate from source files ```python theme={null} cw.assets.rebuild_universal_schema(asset_id) ``` Re-parses the uploaded URDF/MJCF/SDF and regenerates the schema. Useful after uploading new source files or to discard manual edits. *** ## Physics tuning best practices Getting physics parameters right is the difference between a simulation that behaves like the real world and one that explodes on the first contact. This section distills practical guidance from the MuJoCo, Bullet, and Gazebo communities. ### Pick the right timestep The timestep is the single most impactful parameter. Too large and the simulation becomes unstable; too small and you waste compute for no visible gain. | Scenario | Recommended timestep | Notes | | ----------------------------------------- | --------------------- | ----------------------------------------------------- | | General-purpose robotics | **0.001 – 0.002 s** | Safe default; matches most control loops | | High-frequency control (impedance, force) | **0.0003 – 0.0005 s** | Required for stiff contacts and precise force control | | Fast prototyping / locomotion RL | **0.002 – 0.005 s** | Acceptable if contacts are simple | | > 0.005 s | Avoid | High risk of instability, tunneling, and divergence | Your **control timestep must be an exact integer multiple** of the physics timestep. For example, a 50 Hz control loop (0.02 s) with a 0.002 s physics timestep means 10 physics sub-steps per control step. Fractional ratios cause subtle timing bugs. ### Choose a solver type Cyberwave maps solver types to the underlying engine. Use this as a starting point: | Solver | Strengths | When to use | | ----------------- | --------------------------------------- | ------------------------------------------------- | | `quick` (default) | Fast, good general stability | Most use cases — manipulators, mobile robots | | `ode` | Mature LCP solver, predictable friction | Wheeled / skid-steer robots, legacy Gazebo models | | `bullet` | Good for large scenes, GPU-friendly | Multi-robot environments, RL at scale | | `dart` | Accurate analytical LCP | Academic benchmarking, precision contact studies | | `simbody` | Multibody dynamics focus | Biomechanics, articulated soft bodies | Increase `iterations` (default 50) when you see jitter or interpenetration at contacts. Higher iterations improve accuracy at the cost of speed — 100–200 is a reasonable upper bound before you should reduce the timestep instead. ### Tune contact parameters for realism Default contact values are deliberately "grippy" (high friction, low restitution). This works well for tabletop manipulation but may need adjustment for other scenarios. **Friction (`mu_static`, `mu_dynamic`)** | Surface pair | Typical `mu_static` | Typical `mu_dynamic` | | --------------------- | ------------------- | -------------------- | | Rubber on concrete | 0.8 – 1.0 | 0.6 – 0.8 | | Metal on metal | 0.3 – 0.5 | 0.2 – 0.4 | | Plastic on wood | 0.3 – 0.4 | 0.2 – 0.3 | | Teflon / low-friction | 0.04 – 0.1 | 0.03 – 0.08 | When two objects collide, most engines pick the **minimum** friction of the two surfaces. Set friction on your robot's gripper pads separately from the rest of the body. **Restitution (bounciness)** * `0.0` – completely inelastic (objects stick on contact) — good for grippers and heavy payloads * `0.1` – default; slight energy absorption * `0.5 – 0.8` – bouncy; use for balls, elastic impacts * `1.0` – perfectly elastic (no energy loss) — rarely realistic **Stiffness and damping** control how "soft" contacts feel. The defaults (10 000 / 20) model hard rigid bodies. Lower stiffness for deformable objects or compliant surfaces; increase damping if contacts oscillate. ### Prepare for sim-to-real transfer If your goal is to deploy policies trained in simulation onto real hardware, physics parameters are a critical part of the reality gap. **1. Measure, don't guess.** Use a scale, force gauge, or system identification to get real mass, inertia, and joint friction values. Even rough measurements beat defaults — research shows unexpectedly high friction-torque ratios in real joints compared to simulation defaults. **2. Randomize what you can't measure.** Domain randomization over physics parameters helps policies generalize. Randomize friction (±30%), mass (±10%), and contact stiffness across training episodes. This is especially important for contact-rich tasks like assembly or grasping. **3. Validate on simple motions first.** Before training a full policy, compare simulated vs. real joint trajectories on a basic motion (e.g., gravity drop, sine-wave tracking). If these diverge, fix the model before scaling up. **4. Iterate on the timestep last.** Changing the timestep affects controller gains, contact behavior, and training speed simultaneously. Get other parameters right first, then tune timestep if needed. A policy that achieves 95% success in simulation can drop to 30–50% on real hardware without careful parameter calibration. Investing time in physics tuning pays off more than training longer. ### Common pitfalls | Symptom | Likely cause | Fix | | -------------------------------------------- | ------------------------------------- | ------------------------------------------------- | | Objects explode on contact | Timestep too large | Reduce to 0.001 s or lower | | Robot slides on flat ground | Friction too low | Increase `mu_static` to 0.8+ | | Grasped objects slip through fingers | Solver iterations too low | Increase to 100+; check collision geometry | | Joints oscillate / vibrate | Damping too low or timestep too large | Increase contact damping; reduce timestep | | Simulation runs but doesn't match real robot | Default inertia / friction values | Measure real parameters; use domain randomization | | Objects bounce unrealistically | Restitution too high | Set to 0.0 – 0.1 for most rigid contacts | # Unified slug system Source: https://docs.cyberwave.com/feature-reference/concepts/slug-system Human-readable identifiers for workspace entities ## Overview Every major entity in Cyberwave has a **unified, human-readable slug** that uniquely identifies it across the platform. The slug follows a consistent three-segment format: ``` {workspace-slug}/{type-prefix}/{entity-slug} ``` For example: `acme-robotics/catalog/my-robot-arm` ## Type Prefixes | Entity | Type Prefix | Example Slug | | ----------------- | ------------- | ---------------------------------- | | Asset (catalog) | `catalog` | `acme/catalog/my-robot-arm` | | Workflow | `workflows` | `acme/workflows/pick-and-place` | | ML Model | `models` | `acme/models/yolov8-custom` | | Controller Policy | `controllers` | `acme/controllers/keyboard-teleop` | | Environment | `envs` | `acme/envs/production-floor` | | Twin | `twins` | `acme/twins/arm-station-1` | ## URL Format The slug maps directly to the frontend URL: ``` /{workspace-slug}/{type-prefix}/{entity-slug} ``` For example: `/acme-robotics/envs/production-floor` ## API Usage ### Lookup by Slug All entity APIs accept both UUID and slug for lookup. Use the dedicated `by-slug` endpoints when you have a slug: * `GET /api/v1/environments/by-slug?slug={slug}` * `GET /api/v1/twins/by-slug?slug={slug}` * `GET /api/v1/workflows/by-slug?slug={slug}` ### Slug Availability Check Check whether a slug is available before creating an entity: ``` GET /api/v1/slugs/check?slug={workspace/type/entity}&entity_type={type} ``` Response: ```json theme={null} { "available": true, "slug": "acme/envs/my-environment", "suggestion": null } ``` ## Slug Generation Slugs are auto-generated on entity creation from the entity name using Django's `slugify`. Collisions are resolved by appending a numeric suffix: `-2`, `-3`, etc. ## Workspace Rename When a workspace slug changes, all entity slugs are updated automatically to reflect the new workspace prefix. ## Python SDK Usage The Python SDK fully supports unified slugs. Slugs and UUIDs are interchangeable wherever an identifier is accepted. ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() # Fetch entities by slug twin = cw.twin(twin_id="acme/twins/my-arm") env = cw.environments.get_by_slug("acme/envs/production-floor") wf = cw.workflows.get_by_slug("acme/workflows/pick-and-place") # Create a twin using asset slug and environment slug robot = cw.twin("acme/catalog/so101", environment_id="acme/envs/lab") # Trigger a workflow by slug run = cw.workflows.trigger("acme/workflows/pick-and-place", inputs={"speed": 1.0}) # Check slug availability result = cw.assets.check_slug("acme/catalog/my-new-robot") # Access entity slugs print(twin.slug) # "acme/twins/my-arm" print(wf.slug) # "acme/workflows/pick-and-place" ``` ## Deprecation Notices * **`registry_id`** and **`registry_id_alias`** on Assets: deprecated in favor of the unified `slug` field. Will be removed in a future release. * **`catalog_seed_id`** / **`catalog_key`** on ControllerPolicy metadata: deprecated. Use the `slug` field instead. # Create an asset Source: https://docs.cyberwave.com/feature-reference/create-asset Upload your own URDF to create a custom asset, the 3D and kinematic definition behind every digital twin, through the Package, Details and Access steps. An **asset** is the reusable definition of a piece of hardware: its 3D meshes and its kinematic model (URDF) that Cyberwave uses to spawn [digital twins](/feature-reference/architecture/key-concepts). Catalog devices like `the-robot-studio/so101` are assets that already exist. When your hardware **isn't in the [catalog](https://cyberwave.com/catalog)**, you create your own asset by uploading a URDF package. This page walks through creating an asset from the dashboard. You can also upload programmatically, using the REST API or Python SDK methods described on the [Catalog](/feature-reference/catalog) page. *** ## Choose how to create it Open **Add asset** from the catalog or environment editor. | Choice | Best for | What to check | | ----------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | **Describe the object** | Editable dimensions and supported mechanical parts, with an optional reference picture | Review the proposed design and estimated physics. Detailed organic shapes may need another method. | | **Upload a 3D file** | Preserving an existing model's structure and detail | Include referenced files; add the processed asset to your scene from the catalog. | | **From a photo** | Recreating appearance for visual props and organic shapes | A photo is required; description is optional. Scale, hidden surfaces, moving parts and physics need review. | For **Describe the object**, enter your dimensions and intended interaction, then follow **Describe → Review → Use** in the modal header. In **Review**, edit the name, build description and dimensions, or request a change with **Update design**. Review the assumptions, then continue to **Use**. Choose **Private** or **Public** and select **Build object**. Public creation requires confirmation and only publishes the completed catalog object. Your scene does not become public. You can close the dialog while it builds. Catalog creation saves the object in your workspace; starting from an environment also adds the completed object to that scene. The build retains your reviewed design so later revisions have context. Review collision geometry, physical properties and robot reach before training. The following steps cover the **Upload a 3D file** path for a URDF package. ## Prepare your URDF package Cyberwave accepts a single **ZIP archive** containing one main `.urdf` (or `.xacro`) file and every file it references, including meshes, textures, and materials. ```text theme={null} my-robot/ urdf/ robot.urdf meshes/ base_link.stl arm_visual.obj textures/ arm_albedo.png ``` Use **relative paths** inside the URDF that match your ZIP structure. If the URDF references `meshes/arm_visual.obj`, that file must exist at that path inside the ZIP. Cyberwave processes (unpacks and validates) the archive after you create the asset. ZIP uploads can be up to 512 MB, enough for large full-mesh assets like humanoid robots. A complete single-file example (a DJI Mini 4 Pro drone): one `base_link`, four propeller links, and four `continuous` joints. Use it as a reference for link, joint, material, and mesh-reference structure, then bundle your own URDF with its `meshes/` folder into a ZIP. *** ## Create the asset Choose **Upload a 3D file** in **Add asset**, then complete the upload steps. On the **Package** step, drag and drop your ZIP into the **URDF Package (ZIP)** drop zone, or click to select it. The archive should contain your URDF/Xacro plus all referenced meshes. Click **Continue**. Upload URDF package step On the **Details** step, give the asset a clear **name** (for example, `SO-101 workcell`) and a short **description** of what the robot or prop is. Describe your asset step Expand **Advanced** for two optional fields: * **Main URDF path**: the path to the main URDF inside the ZIP (for example, `urdf/robot.urdf`). Leave it blank to auto-detect the URDF inside the archive, and set it only when the ZIP contains more than one URDF. * **Thumbnail**: an optional preview image (PNG or JPG) for the asset card. Advanced asset details Click **Continue**. On the **Access** step, choose who can see and use the asset, then pick the **workspace** it belongs to. | Visibility | Who can view | | ---------------- | -------------------------------- | | **Private** | Only you | | **Organization** | All members of your organization | | **Public** | Anyone on the platform | Choose asset access step Click **Create Asset**. Cyberwave processes the archive, and once it's ready the asset is available to spawn twins from, in the dashboard, the [Python SDK](/overview/tools/python-sdk), or the REST API. Start **Private** while you iterate on the URDF and driver, then switch the asset to **Organization** or **Public** when it's ready to share. Visibility can be changed after creation. *** ## Next steps Connect your hardware's native API to the new asset's twin so it streams and takes commands in real time. The full overview for bringing your own hardware online with Cyberwave. # When episodes fail Source: https://docs.cyberwave.com/feature-reference/datasets/episode-failures Why a dataset can be marked failed, what you can still do with it, and how to fix it A dataset is built from episodes, and an episode can fail to build. Cyberwave never lets a dataset look healthy when it isn't — the dataset is marked **Failed**, and each episode shows why. ## A failed episode fails the dataset If any episode fails, the dataset is marked **Failed** and cannot be used to start a training. This is deliberate: training on a dataset that quietly lost part of its data produces a model you cannot trust. Open the dataset to see which episodes failed and the reason for each. ## Fixing it **Remove the failing episode** from the dataset. The dataset becomes usable again straight away. If the episode's data matters to you, record it again — or contact support if you believe the recording itself is intact. ## Exports still work You can still export a dataset that has a small number of failed episodes — the export is built from the episodes that are valid, and tells you how many were skipped. If more than 10% of the episodes are unusable, the export stops instead of producing a badly incomplete file. ## Episodes recorded with different cameras Episodes recorded with different cameras can be combined into one dataset, as long as each episode has the **same number** of cameras. The cameras are lined up by position: the first camera of every episode becomes the dataset's first camera, and so on. If an episode is missing a camera, it is skipped rather than guessed at. ## Episodes still recording If you try to create a dataset while one of its recordings is still being processed, Cyberwave tells you which episodes are affected and lets you choose: wait and retry, drop those episodes, or continue anyway. If you continue, those episodes may be incomplete — they will be marked failed rather than silently shortened. Waiting until processing finishes and then creating the dataset is the safe choice. ## Creating and recomputing a dataset is asynchronous Creating a dataset (or recomputing one) returns right away — the dataset appears immediately with a **Queued** or **Generating** status. Keep polling the dataset until it reaches **Ready** or **Failed**. If the selected episodes don't share the same number of robot or camera recordings, that also surfaces as a **Failed** dataset with a reason, the same way an individual episode failure does. # Dataset export & format conversion Source: https://docs.cyberwave.com/feature-reference/datasets/format-conversion Download and convert robot datasets to different formats from the UI, SDK, or API. **Robot datasets first.** Export and format conversion is available for robot datasets (LeRobot, RLDS, Cyberwave Parquet, and other Forge-readable sources). Support for image, video, audio, and multimodal dataset formats is planned for a future release. ## Export tab (UI) Every robot dataset detail page has an **Export** tab alongside Overview, Files, and Code. It shows a matrix of all supported output formats with their current status and a one-click conversion flow. * **Convert** — starts a conversion job for that format; the row updates live as the job runs * **Download** — available once a conversion is ready; generates a fresh 24-hour signed URL * **Retry** — re-triggers a failed conversion Datasets whose source format is not a robot format (image directories, COCO, FiftyOne, etc.) show a "Conversion not available" message in the Export tab. Formats marked **Coming soon** are planned but not yet validated end-to-end. Clicking Convert on them records your interest so we can prioritise accordingly. ## Including audio If your recordings include microphone audio, tick **Include audio** when creating the dataset (or set `include_audio: true` on the create request). It is **off by default**, so existing exports are unchanged. When enabled, the export bundle gains an `audio/` folder: * one trimmed MP3 per episode and microphone, covering that episode's time window * an `audio/manifest.json` that maps each clip to the dataset rows (by episode) so you can line audio up with the state/action timeline The audio travels **alongside** the data as companion files — it is never mixed into the parquet. This is a Cyberwave companion format for portability across export formats; it is not a native audio feature of the LeRobot dataset spec, so LeRobot tooling will not auto-load it as audio. ## Download endpoint ```http theme={null} GET /api/v1/datasets/{uuid}/download?format= ``` This endpoint is **idempotent**: calling it multiple times does not spawn duplicate conversion tasks. ### Supported output formats | `format` value | Description | Status | | ------------------------------- | --------------------------------------------------------------- | :------------: | | `parquet` *(alias: `plain`)* | Cyberwave joined-parquet zip — native robot format | ✓ Available | | `lerobot3` *(alias: `lerobot`)* | LeRobot v3 (HuggingFace, Parquet + MP4) | ✓ Available | | `rlds` | RLDS / TF-Record (Open-X-Embodiment style) | ✓ Available | | `openvla` | Cyberwave OpenVLA TFDS bundle (requires camera role assignment) | ✓ Available | | `robodm` | Berkeley .vla format | 🔜 Coming soon | | `mcap` | MCAP (Foxglove) | 🔜 Coming soon | | `gr00t` | NVIDIA GR00T | 🔜 Coming soon | | `hdf5` | HDF5 | 🔜 Coming soon | | `zarr` | Zarr | 🔜 Coming soon | | `rosbag` | ROS bag | 🔜 Coming soon | `lerobot21` is no longer a separate output format. The backend normalises LeRobot v2.1 source datasets to `lerobot3` automatically. Deprecated aliases `plain` and `lerobot` are accepted but new integrations should use the canonical values. ### Response codes | Code | Meaning | | ----- | --------------------------------------------------------------------------------- | | `200` | Artifact is ready — `signed_url` is valid for 24 hours | | `202` | Conversion is queued or running — poll until you get a `200` | | `422` | Format not yet supported (coming-soon targets), or dataset is not a robot dataset | ### Example — artifact ready (200) ```json theme={null} { "format": "lerobot3", "status": "ready", "signed_url": "https://storage.googleapis.com/...", "expires_at": "2026-05-05T15:00:00+00:00", "processed_dataset_uuid": "a1b2c3d4-..." } ``` ### Example — conversion in progress (202) ```json theme={null} { "format": "rlds", "status": "queued", "message": "Dataset conversion to 'rlds' is queued. Poll /api/v1/datasets/.../download?format=rlds until status is 'ready'.", "processed_dataset_uuid": "a1b2c3d4-...", "poll_url": "/api/v1/datasets/{uuid}/download?format=rlds" } ``` ## Python SDK ```python theme={null} import time from cyberwave import Cyberwave cw = Cyberwave(api_key="...") ds = cw.datasets.get("dataset-uuid") # Request a specific output format — triggers conversion if needed and # polls until it is ready. Returns the signed download URL (valid 24 h). url = cw.datasets.convert(ds, "lerobot3") print(url) # Or convert and save the file in one call: path = cw.datasets.download(ds, "lerobot3", dest="./data") ``` ## MCP tool ``` cw_download_dataset(dataset_uuid, format) ``` Returns `signed_url` when ready (`status: ready`) or `status: queued / processing` with a `poll_url` when conversion is in flight. ## Source formats (import / detection) Cyberwave detects the source format of imported datasets and stores it on the dataset record. Only robot source formats are eligible for conversion. | Source format | Description | Conversion eligible | | -------------------------- | ------------------------------------------------------------- | :-----------------: | | `cyberwave_parquet` | Cyberwave native joined-parquet (natively generated datasets) | ✓ | | `lerobot3` | LeRobot v3 | ✓ | | `lerobot21` | LeRobot v2.1 (normalised to `lerobot3` for output) | ✓ | | `lerobot` | LeRobot (version not yet determined) | ✓ | | `rlds` | TFDS / Open-X-Embodiment | ✓ | | `gr00t` | NVIDIA Isaac GR00T | ✓ | | `robodm` | Berkeley .vla | ✓ | | `hdf5` | Robomimic / ACT / ALOHA | ✓ | | `zarr` | Diffusion Policy / UMI | ✓ | | `mcap` | ROS2 CDR + Foxglove Protobuf | ✓ | | `rosbag` | ROS1 .bag / ROS2 SQLite3 | ✓ | | Image / video / CV formats | COCO, YOLO, VOC, ImageNet, FiftyOne, etc. | — Not yet | ## ML Training When you start an ML training from a robot dataset, Cyberwave converts it to the required format automatically. Training launches once conversion completes — no manual action needed. Camera role assignment is required for multi-camera imported datasets when using the `openvla` format. # Import datasets Source: https://docs.cyberwave.com/feature-reference/datasets/import Import robot datasets from HuggingFace Hub or upload zip files. **Robot datasets first.** Cyberwave currently focuses on robot manipulation and navigation datasets (LeRobot, RLDS, and similar time-series formats). Zip upload supports LeRobot only; HuggingFace Hub import detects any dataset repository, but only robotics datasets are correctly displayed today. Full support for non-robotics formats — playback, conversion, and training — is coming in a future release. ## Overview Cyberwave supports importing datasets from two sources: * **HuggingFace Hub** — Import directly by repository ID (lazy, no multi-GB copy) * **Zip Upload** — Upload a pre-packaged dataset archive (max 10 GB) Format detection happens automatically on the server side and sets the `source_format` field on the dataset record. ## Supported formats The two import sources have different levels of format support today. ### Zip upload — LeRobot only Zip upload currently supports **LeRobot v2.1 and v3 only**. Other dataset formats are not yet supported via zip upload. | Format | `source_format` value | Description | | ------------ | --------------------- | -------------------------------------------------------------- | | LeRobot v3 | `lerobot3` | Latest LeRobot format — parquet episodes + `meta/info.json` | | LeRobot v2.1 | `lerobot21` | Legacy LeRobot format with splits (normalised to v3 on export) | ### HuggingFace Hub — broader import, robotics-only display HuggingFace Hub import works for **any dataset repository** — Cyberwave queries the repo and detects its format automatically regardless of what kind of dataset it is. However, only **robotics datasets** are correctly displayed and usable in Cyberwave today. | Category | Examples | Status via HuggingFace import | | ---------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------- | | Robotics / time-series | LeRobot, RLDS, HDF5, Zarr, GR00T, RoboDM, MCAP, ROS bag | Detected and correctly shown | | Everything else | COCO, YOLO, ImageNet, video/audio, CVAT, and other image/video/CV formats | Detected and cataloged, but not yet correctly shown or usable | Playback, conversion, and ML training are fully wired up only for LeRobot today. Other robotics formats imported from HuggingFace are recorded correctly (`source_format`, sample counts) but full episode playback is still being built out. ## Import from HuggingFace Hub 1. Navigate to your workspace and click **Import Dataset** 2. Select **HuggingFace Hub** as the source 3. Enter the repository ID (e.g. `lerobot/pusht`) 4. Click **Import** HuggingFace imports are **lazy by default**: Cyberwave queries the HF API for tags, card data, and the file list, and for LeRobot datasets reads only the small `meta/*.json` files. The dataset card appears immediately with episode counts, FPS, robot type, and cameras — without copying the multi-GB payload. Frames are fetched on demand when a training run or visualisation needs them. The `metadata.import.materialized` flag stays `false` until a follow-up materialisation step runs. Any repository can be imported this way — Cyberwave will detect and catalog whatever format it finds — but only robotics datasets are correctly displayed and usable today (see [Supported formats](#supported-formats)). For private HuggingFace repositories, ensure your organisation has configured the HuggingFace token in the deployment settings. ## Upload a zip file 1. Navigate to your workspace and click **Import Dataset** 2. Select **Upload Zip** as the source 3. Select your zip file (max 10 GB) 4. Click **Upload** The system automatically detects the format after the upload completes. Zip upload only supports **LeRobot** (v2.1/v3) today (see [Supported formats](#supported-formats)); other formats should be imported from HuggingFace Hub instead. ## Monitor progress After starting an import you can track it via: * The dataset list view (status indicator) * The dataset detail page (`metadata.upload_progress`) ## API reference Initialise a dataset import. Returns a signed URL for zip uploads, or immediately starts an HF import. Complete a zip upload import after the file has been uploaded to the signed URL. See the [API Reference](/api-reference/rest/DefaultApi) for full details. ## Upload a LeRobot dataset Cyberwave supports uploading pre-built LeRobot datasets directly to your workspace. This allows you to use existing datasets for VLA model fine-tuning without re-collecting data in Cyberwave. Supported formats: * **LeRobot v2.1** - Legacy format with splits-based episode organization * **LeRobot v3.0** - Current format with chunked data and episodes.jsonl ### Quick Start 1. Open an environment in the Cyberwave editor 2. Navigate to **File → Import → Upload dataset** 3. Fill in the dataset name and select your `.zip` file 4. Wait for processing to complete 5. Your dataset is now available under **Data → Manage Datasets** ### Dataset Requirements Your LeRobot dataset zip file should contain: ``` your-dataset.zip/ ├── meta/ │ ├── info.json # Required: dataset metadata │ └── episodes.jsonl # v3.0 only ├── data/ │ └── chunk-000/ │ └── *.parquet # Episode data └── videos/ # Optional: video files └── chunk-000/ └── *.mp4 ``` The `meta/info.json` file must include: * `codebase_version` - Version string (e.g., "v3.0" or "v2.1") * `fps` - Recording frame rate * `features` - Feature definitions including action/observation shapes ### Size Limits * Maximum file size: 10 GB * Large uploads (>2 GB) may take several minutes ### Processing Stages After upload, Cyberwave automatically: 1. **Downloads** the zip to processing workers 2. **Extracts** and validates the archive structure 3. **Detects** the format version (v2.1 or v3.0) 4. **Validates** data integrity and required files 5. **Persists** metadata and creates dataset records You can monitor progress in real-time through the upload dialog. ### Using Uploaded Datasets Once processed, your dataset can be used for: * **VLA Fine-tuning** - Train SmolVLA or other models on your data * **Export** - Download in different formats * **Review** - Browse episodes and metadata ### Related * [SmolVLA Training](/feature-reference/ml-models/smolvla-training) * [Model catalog](/feature-reference/ml-models) # Dataset playground Source: https://docs.cyberwave.com/feature-reference/datasets/playground Explore robot datasets with synchronised video, low-dimensional plots, and a scrubbable timeline. **Robot datasets first.** The playground currently supports LeRobot v2.1 and v3 datasets, imported from HuggingFace or uploaded as zip files. Playback for other dataset types (image classification, video, audio, multimodal) is coming in a future release. ## Overview The Dataset Playground lets you open an imported robot dataset in a structured viewer with: * Synchronised episode video (wrist + external cameras) * Low-dimensional data plots (joint positions, velocities, actions) * A scrubbable timeline for frame-by-frame inspection ### Supported formats | Format | Status | | ----------------------------------------- | :---------------: | | LeRobot v3 | ✓ Available | | LeRobot v2.1 | ✓ Available | | Other robot formats (RLDS, HDF5, Zarr, …) | 🔜 Coming soon | | Image / video / CV datasets | — Not yet planned | ### Related API * `GET /api/v1/datasets/by-slug` * `GET /api/v1/datasets/{uuid}/episode-manifest` * `GET /api/v1/datasets/{uuid}/resolve` ## Multi-format datasets **Robot datasets first.** The multi-format playground is being built specifically for robot manipulation and navigation datasets. Image, video, audio, and generic multimodal dataset formats are not in scope for the initial release. The multi-format playground extends the standard Dataset Playground with support for additional robot dataset formats beyond LeRobot, providing a unified viewer regardless of the original source format. #### Supported formats (current & planned) | Format | Status | | --------------------------- | :--------------------------------: | | LeRobot v3 | ✓ Available | | LeRobot v2.1 | ✓ Available | | Cyberwave OpenVLA | ✓ Available | | RLDS / TF-Record | 🔜 Coming soon | | HDF5 (Robomimic / ACT) | 🔜 Coming soon | | Zarr (Diffusion Policy) | 🔜 Coming soon | | GR00T | 🔜 Coming soon | | Image / video / CV datasets | — Not in scope for initial release | #### Implementation reference * Backend: `cyberwave-backend/src/lib/data/dataset/manifest/` and `section_info/` * Frontend: `cyberwave-frontend/components/datasets/playgrounds/` # Work with digital twins Source: https://docs.cyberwave.com/feature-reference/digital-twins Virtual replicas of physical robots that mirror behavior, capabilities, and environment in real-time ## What is a digital twin? A digital twin is a virtual replica of a physical robot that mirrors its behavior, capabilities, and environment in real-time. It serves as a bridge between the physical and digital worlds — enabling you to simulate, test, control, and monitor your robots from anywhere. A digital twin includes a 3D model, physics simulation, sensor integration, and real-time bidirectional sync with the physical robot via Edge Core. *** ## Why use digital twins? Test dangerous or complex scenarios without risking physical hardware Iterate and optimize algorithms in simulation before deployment Monitor and control robots from anywhere in the world Test fleet behaviors and multi-robot coordination *** ## Capabilities Map Twin behavior in Cyberwave is capability-driven. The platform computes capabilities from each twin's `universal_schema`, and those values control which UI panels, controls, and SDK behaviors are available. ### Core Capabilities | Capability | Type | Description | | ------------------------------- | ------- | ------------------------------------------------------------------------------------- | | `can_locomote` | boolean | Twin can move through the environment (navigation/locomotion) | | `can_fly` | boolean | Twin supports aerial movement | | `can_grip` | boolean | Twin has a gripper/end-effector for grasping | | `can_actuate` | boolean | Twin has actuators that can be commanded (e.g. joints) | | `has_joints` | boolean | Twin has controllable joints | | `has_wheels` | boolean | Twin has wheel-based locomotion hardware | | `has_legs` | boolean | Twin has legged locomotion hardware | | `manipulator_count` | number | Number of manipulators/end-effectors | | `payload_capacity_kg` | number | Max payload supported by manipulation system (kg) | | `power_source` | enum | `battery`, `tethered`, `rails`, `fuel`, `solar`, `hybrid` | | `power_capacity_wh` | number | Power capacity in Wh (`-1` = unknown/not applicable) | | `navigation_autonomy_level` | enum | `manual`, `waypoint`, `path_following`, `semi_autonomous`, `fully_autonomous`, `none` | | `navigation_obstacle_avoidance` | boolean | Whether built-in obstacle avoidance is available | | `locomotion_mode` | enum | `stationary`, `wheeled`, `tracked`, `legged`, `aerial`, `surface`, `subsea`, `hybrid` | | `locomotion_config` | object | Locomotion limits/config (max linear/angular velocity, DOF) | | `sensors` | array | Sensor definitions attached to the twin | ### Sensor Capabilities `sensors` is an array of sensor entries inside `capabilities`. If a twin has one or more sensor entries, sensor-driven features become available in both UI and SDK flows. | Field | Type | Description | | ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Stable sensor identifier (e.g. `wrist_camera`) | | `type` | enum | `rgb`, `depth`, `lidar_2d`, `lidar_3d`, `lidar_4d`, `map`, `audio`, `audio_mono`, `audio_stereo`, `gps`, `compass`, `imu`, `flashlight` | | `model` | string | Optional hardware/model label | | `offset.position` | object | Position offset from twin origin (`x`, `y`, `z`) | | `offset.rotation` | object | Rotation offset quaternion (`x`, `y`, `z`, `w`) | | `fov_degrees` | number | Optional camera FOV override | | `width`, `height` | number | Optional image resolution (camera sensors) | | `min_range`, `max_range` | number | Optional range values (depth/lidar sensors) | | `points_per_second` | number | Optional lidar density/throughput hint | | `velocity_sensing` | boolean | Optional 4D lidar velocity support flag | | `update_rate` | number | Optional update frequency (Hz) | ### Feature-to-Capability Matrix | Feature | Capability condition | | ------------------------------------------ | ------------------------------------------------------------------- | | **Joint movement and editing** | `can_actuate = true` (typically with `has_joints = true`) | | **Re-calibrate driver action (Live mode)** | `can_actuate = true` | | **Missions editor/simulation** | `can_locomote = true` | | **Sensor windows (Live + Simulate)** | `sensors.length > 0` | | **Point cloud rendering** | Sensor type includes `depth` or `lidar_*` | | **Controller policy UI** | `has_joints` OR `can_locomote` OR `can_actuate` OR `can_grip` | | **Edge connection status (Live mode)** | `sensors.length > 0` OR controllable twin | | **SDK twin class selection** | Combination of `can_locomote`, `can_fly`, `can_grip`, and `sensors` | | **SDK camera streaming** | `sensors` includes camera sensors (`rgb`/`depth`) | `canHaveMissions` currently maps to `can_locomote`, and "controllable twin" maps to `has_joints OR can_locomote OR can_actuate OR can_grip`. *** ## Cloud Recording By default, Cyberwave saves video and audio recordings from every twin session to cloud storage. You can disable this per twin if you do not need cloud-stored recordings (for example, during development or for privacy reasons). The toggle applies to any twin with a camera (RGB or depth) and/or a microphone sensor. The setting governs **both** video and audio in a single flag. ### Seeing the current state When a twin with recordable sensors is selected, the twin editor header shows a small icon next to its name: * A **muted camera or microphone icon** means cloud recording is on. * An **amber camera-off or microphone-off icon** means cloud recording is off — sessions are still tracked, but no media is stored. The icon family matches what the twin actually records: a camera glyph for twins with a camera, a microphone glyph for audio-only twins. Hover the icon to see the full tooltip, including which media types are covered. ### Disabling cloud recording Open the twin editor in an environment, click the **three-dot menu** (⋯), and select **Disable cloud recording**. The option is available for any twin that has at least one camera or microphone sensor. When cloud recording is disabled: * Telemetry lifecycle events (start/stop) are still logged normally. * Camera recording generation tasks (parquet, MP4) are **not** spawned. * Audio MP3 conversion tasks are **not** spawned. * No video or audio artifacts are uploaded to cloud storage for that twin. To re-enable, open the same menu and select **Enable cloud recording**. The setting is stored in `twin.metadata.cloud_recording_enabled`. When the key is absent or `true`, recordings are saved (default behavior). Set it to `false` to disable. LiDAR point clouds are not currently gated by this flag. *** ## Related Control physical robots through their digital twins in real time Set up 3D environments for your twins Browse pre-built robot assets to create twins # Coupled and passive joints Source: https://docs.cyberwave.com/feature-reference/digital-twins/mimic-joints Which joints you can command directly, and how coupled, passive and fixed joints affect manual input mappings. In **Control**, map keys, gamepad axes or a leader arm to the robot's independent joints. A joint can move in the 3D model without being independently commandable. * **Coupled joints** follow another joint. For example, a gripper can expose one finger control while both fingers move together. * **Passive joints** move with the mechanism but have no independent input. * **Fixed joints** cannot move and have no joint control. These choices come from the robot's declared configuration. Missing actuator information on an older asset does not establish which joints are passive. ## Configure the input 1. Open the asset's **Control** tab, or select the twin in **Workbench → Control**. 2. Select **Joint target control**, then configure an input such as **Keyboard**. 3. Assign a key pair to an independent joint and save. A PiPER gripper with the declared finger coupling uses `joint7`; `joint8` is not a second manual target. 4. Review the keys together in **Overview**. Saving a mapping does not start motion. Twin-specific mappings customize a reusable input without changing its template. Existing mappings remain available for review; after changing a robot's joint configuration, review them before use. Model outputs and leader mappings must also match the independently commandable joints. ## Check the result Use a supported runtime and compare the commanded target with measured joint feedback. A correct-looking 3D pose alone does not prove hardware movement. If a coupled mechanism moves incorrectly, review its declared coupling, joint limits and driver configuration instead of adding a separate key for the follower. Control physical robots through the environment editor Capabilities, pairing, and twin concepts # Docker registry Source: https://docs.cyberwave.com/feature-reference/docker-registry Use the Cyberwave Docker Registry to pull and push custom drivers and AI models and re-use them across your robots and automations ## Overview The Docker Registry is available on **Cyberwave Enterprise** plans. Contact us at [info@cyberwave.com](mailto:info@cyberwave.com) to enable it for your organization. Cyberwave hosts a private Docker registry at `registry.cyberwave.com`. You use it to store and distribute the container images that run on your robots and cloud nodes — drivers, ML models, custom ROS packages, and anything else your edge devices need. Authentication uses the same `CYBERWAVE_API_KEY` you already use for the REST API and MQTT. Your workspace role determines what you can do: | Workspace role | Registry access | | -------------- | ----------------------------- | | READER | Pull images | | WRITER | Pull and push images | | ADMIN | Pull, push, and delete images | | OWNER | Full access | There are no separate registry passwords. The same API key and workspace membership that govern REST and MQTT access also govern registry access. *** ## Setup If you haven't already, install the CLI. It includes the Docker credential helper. ```bash theme={null} pip install cyberwave-cli ``` Use the same environment variable the SDK and CLI already read: ```bash theme={null} export CYBERWAVE_API_KEY="cw_your_token_here" ``` Authenticate Docker against `registry.cyberwave.com` before pulling private images or pushing. If you prefer not to install the credential helper, you can log in explicitly: ```bash theme={null} echo "$CYBERWAVE_API_KEY" | docker login registry.cyberwave.com \ -u you@example.com --password-stdin ``` `docker login ` targets that specific registry, not Docker Hub. Credentials are cached locally until they expire or you run `docker logout registry.cyberwave.com`. *** ## Pulling images ### Public images Public images (e.g. Cyberwave-maintained drivers) require no authentication: ```bash theme={null} docker pull registry.cyberwave.com/public-drivers/ugv-driver:v1.2.3 ``` For production, pin by digest instead of tag: ```bash theme={null} docker pull registry.cyberwave.com/public-drivers/ugv-driver@sha256: ``` ### Private images Private images require authentication. Your workspace role must grant at least READER access: ```bash theme={null} docker pull registry.cyberwave.com/my-workspace/navigation-driver:v2.0.0 ``` If you have access, the pull succeeds. If not, it fails with `403` — the same behavior as trying to access a REST endpoint or MQTT topic without the right role. *** ## Pushing images To push, your workspace role must grant at least WRITER access. Tag it with the full registry path. The path includes your workspace or project namespace: ```bash theme={null} docker build -t registry.cyberwave.com/my-workspace/my-driver:v0.1.0 . ``` ```bash theme={null} docker push registry.cyberwave.com/my-workspace/my-driver:v0.1.0 ``` If the credential helper is configured, no separate login step is needed. The Cyberwave Token Service validates your API key, checks your workspace role, and authorizes the push. Version tags (e.g. `v1.2.3`) are immutable — once pushed, they cannot be overwritten. Use mutable tags like `dev` or `latest` during development. *** ## Using registry images on edge devices Reference registry images in your `cyberwave.yml` driver configuration: ```yaml theme={null} driver: docker_image: registry.cyberwave.com/public-drivers/ugv-driver:v1.2.3 ``` Edge Core pulls the image automatically when the twin connects. If the image is private, the edge device authenticates using the API key configured during device setup. *** ## Tagging conventions | Tag pattern | Meaning | Mutable? | | ---------------- | ------------------- | -------------- | | `v1.2.3` | Release version | No (immutable) | | `latest` | Most recent release | Yes | | `dev` | Development build | Yes | | `-` | CI build | Yes | *** ## CI/CD integration In GitHub Actions or other CI systems, authenticate using a Cyberwave service API key: ```yaml theme={null} - name: Login to Cyberwave registry run: | echo "${{ secrets.CYBERWAVE_CI_API_KEY }}" | docker login registry.cyberwave.com \ -u ci@cyberwave.com --password-stdin - name: Build and push run: | docker build -t registry.cyberwave.com/my-workspace/my-driver:${{ github.sha }} . docker push registry.cyberwave.com/my-workspace/my-driver:${{ github.sha }} ``` The CI API key is a normal Cyberwave API key whose workspace membership grants WRITER access to the target project. *** ## Architecture The registry uses [Harbor](https://goharbor.io/) with a Cyberwave-managed token service. When Docker needs to authenticate, the flow is: ```mermaid theme={null} sequenceDiagram participant D as Docker Client participant H as Harbor (registry.cyberwave.com) participant T as Cyberwave Token Service D->>H: 1. docker pull / push H-->>D: 2. 401 + token endpoint URL D->>T: 3. Request token with CYBERWAVE_API_KEY T->>T: 4. Validate key & resolve workspace role T-->>D: 5. Scoped JWT (pull, push, delete) D->>H: 6. Retry with JWT H-->>D: 7. Serve the request ``` The token service is a standard Docker Registry v2 token endpoint backed by the Cyberwave auth and ACL system. Harbor handles image storage, vulnerability scanning, replication, and retention policies. # Alerts Source: https://docs.cyberwave.com/feature-reference/edge/drivers/alerts Alerts notify operators that action is needed. Alerts notify operators that action is needed. They are displayed prominently in the UI (environment view, twin detail, etc.). Alerts have a **category**: * **technical** (default): operational or hardware events (e.g. robot stuck, calibration needed). * **business**: business-process events (e.g. order delayed, SLA threshold exceeded). Examples: * A robot needs calibration. * A robot got stuck and needs remote takeover. * A sensor reading is out of expected range. * An order has exceeded its SLA deadline. ## Model Every alert belongs to a workspace and must be attached to at least one of: twin, environment, or workflow. | Field | Type | Notes | | ------------- | ------ | -------------------------------------------------------------------- | | `name` | string | Human-readable title | | `description` | text | Optional details | | `alert_type` | string | Machine-readable code (e.g. `calibration_needed`, `robot_stuck`) | | `severity` | enum | `info`, `warning`, `error`, `critical` (default: `warning`) | | `status` | enum | `active`, `acknowledged`, `resolved`, `silenced` (default: `active`) | | `source_type` | enum | `edge`, `simulation`, `cloud`, `workflow` (default: `edge`) | | `category` | enum | `technical`, `business` (default: `technical`) | ## Lifecycle * **Active**: new alert, requires attention. * **Acknowledged**: an operator has seen it but the issue is not yet fixed. * **Resolved**: the root cause has been addressed (by edge device or operator). * **Silenced**: suppressed workspace-wide without resolving the root cause. ## Idempotent resolve and silence The `POST /api/v1/alerts/{uuid}/resolve` and `POST /api/v1/alerts/{uuid}/silence` endpoints are **idempotent**: * Resolving an already-resolved alert returns `200` with the alert body (no-op). * Resolving a silenced alert is allowed — it transitions the alert to resolved. * Silencing an already-silenced alert returns `200` with the alert body (no-op). * Silencing a resolved alert returns `400`. This means edge drivers and operator UIs can safely call resolve without checking current status first, avoiding race conditions when multiple actors act on the same alert concurrently. ## Workflow-scoped alerts Alerts produced by a workflow's `send_alert` node carry a `workflow_uuid`, and `Alert.workflow` is set on the backend. List alerts for a single workflow with: ```text theme={null} GET /api/v1/alerts?workflow_uuid={workflow_uuid} ``` Generated edge workers call `client.publish_alert(..., workflow_uuid=WORKFLOW_UUID, workflow_node_uuid=..., workflow_execution_uuid=...)`. The SDK forwards `workflow_uuid` as a top-level field (sets the FK) and merges `workflow_node_uuid` / `workflow_execution_uuid` into `metadata` for full provenance. When an alert is attributable to one node, the alert card also shows a `Node: ()` badge (from `metadata.workflow_node_name` / `metadata.workflow_node_type`), and a `POST /activate` rejection returns that same node identity in the response body so the editor can highlight the offending node directly instead of showing a generic failure message. ## Source attribution: `metadata.source_chain` Every alert raised by a workflow's `send_alert` node carries an ordered `source_chain` under `metadata` describing each upstream node that fed into the decision. The chain is built generically — any node emitter that opts in by parking a `_source_summary` on its output dict contributes an entry, so the mechanism works equally well for camera-perception, audio-track, alert-triggered, manual, scheduled, or any future trigger source. Each entry includes: * `kind` — short identifier (`camera_frame`, `audio_track`, `alert_trigger`, `manual_trigger`, `schedule_trigger`, `call_model`, `detection_event_gate`, `conditional`). * `node_uuid` — the workflow node that contributed the entry. * Kind-specific fields. Examples: `twin_uuid` + `sensor` for camera/audio triggers; `model_uuid` + `model_name` + a capped `detections_sample` for `call_model`; `mode` + `matched_classes` + `cooldown_seconds` for `detection_event_gate`. Example payload for a `camera_frame → call_model → send_alert` workflow: ```json theme={null} { "metadata": { "workflow_uuid": "...", "workflow_node_uuid": "...", "workflow_execution_uuid": "...", "source_chain": [ { "kind": "camera_frame", "node_uuid": "...", "twin_uuid": "...", "sensor": "front", "frame_ts": 1746651234.5 }, { "kind": "call_model", "node_uuid": "...", "model_uuid": "...", "model_name": "YOLOv8n", "modality": "image", "output_format": "detections", "detections_total": 2, "detections_sample": [ { "label": "person", "confidence": 0.91, "bbox_pixels": [12, 34, 56, 78] } ] } ] } } ``` Notes: * The chain is purely additive. Adding `_source_summary` does not change `dedupe_hash` (computed over `name + description + alert_type + severity + status + twin_uuid`), so dedupe behavior is unchanged. * `detections_sample` is capped to keep alert metadata bounded; the original `detections_total` is preserved. * User-supplied static `metadata` keys always win on conflict — the source chain only fills in `metadata['source_chain']` when not already provided. ## Edge Core system alerts Edge Core automatically raises technical alerts for operational issues. These are `category: technical`, `source_type: edge` unless noted otherwise. | `alert_type` | Severity | Source | Trigger | | ------------------------------------- | -------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `driver_start_failure` | `error` | `edge` | Driver container cannot reach a stable running state | | `driver_restart_loop` | `error` | `edge` | Driver restarts too frequently (circuit-breaker tripped) | | `driver_health` | `warning` | `edge` | Driver container stopped unexpectedly | | `model_download_failure` | `warning` | `edge` | Required ML model could not be downloaded | | `worker_start_failure` | `warning` | `edge` | Worker container failed to start | | `workflow_activation_error` | `error` | `workflow` | You tried to activate a workflow that's invalid or missing a required input — activation is blocked and the alert names the specific node and field that need fixing. Clears once the workflow activates successfully. | | `workflow_compile_error` | `error` | `workflow` | An active workflow couldn't be compiled for the edge, so it won't run there until fixed. The alert explains why; scoped to the twin the failing node targets when applicable. Clears automatically once the workflow compiles successfully. | | `workflow_sync_failure` | `error` | `edge` | The edge could not download one or more workflow workers from the cloud — affected workflows won't run on that twin until the next successful sync | | `worker_load_error` | `error` | `edge` | A workflow worker on the edge failed to load and will not run | | `worker_runtime_error` | `error` | `edge` / `cloud` | A workflow node raised an error while running. Attached to the workflow (and twin) so you can find it from the workflow. Appears the same way whether the workflow runs on edge or cloud — only `source_type` differs. | | `driver_starting` / `worker_starting` | `info` while starting, `critical` on failure | `edge` | Tracks a driver/worker container coming up, through three stages: downloading the image, installing (decompressing) it, and starting the container. It clears once the container is running, so a worker whose image is already downloaded still reports that it is starting. A failed pull (including a timed-out download of the driver image, the ML worker image, or any other required image) flips the alert to `critical` before resolving it — never a quiet `warning`. | | `edge_core_restart` | `info` | `cloud` | Backend has accepted an edge-core restart request and is tracking the lifecycle (see below) | ### `edge_core_restart` lifecycle alert `POST /api/v1/edges/{uuid}/restart-core` creates a single `edge_core_restart` alert that tracks the restart end-to-end. The alert is scoped to the environment of the first bound twin (alerts always need a twin / environment / workflow anchor), with `source_type: cloud` because the request originates from the backend, not from the edge. The current phase is carried on `metadata.phase`: | Phase | Written by | Meaning | | ------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | | `requested` | Backend, on accepting the API call | MQTT restart command queued | | `in_progress` | Edge-core, when it picks the command off MQTT | Restart actually running | | `completed` | Edge-core, after a successful relaunch | Happy path; alert is resolved | | `failed` | Edge-core, if `_perform_edge_core_restart` raises | Restart attempt failed; alert resolved with `phase: failed` | | `timed_out` | Backend reaper (`reap_stuck_edge_core_restart_alerts`) | Alert stuck in `requested` / `in_progress` past 5 min — typically the MQTT command never landed or edge-core crashed mid-restart | The same `alert_uuid` is returned in the API response **and** included in the MQTT command payload, so edge-core can transition the alert without a lookup. ### Restart-driven pre-resolution When `restart-core` is accepted, the backend also pre-resolves any active alerts on the requesting edge's bound twins whose root cause a clean container relaunch genuinely fixes: * `driver_start_failure` * `driver_restart_loop` * `worker_start_failure` This keeps the workbench from carrying stale failure noise that the operator's restart just made irrelevant. Each pre-resolved alert is annotated with: ```json theme={null} { "metadata": { "resolved_by_restart_request_id": "", "resolved_by_restart_alert_uuid": "" } } ``` and the `edge_core_restart` alert's own metadata gets `pre_resolved_alert_uuids: [...]` so the audit trail links both ways. Other alert types are deliberately **not** pre-resolved (a restart doesn't actually fix them, and silently closing them would lie to the operator). The authoritative allow-list and excluded set live on [`EDGE_CORE_RESTART_RESOLVABLE_ALERT_TYPES`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-backend/src/app/api/edge_nodes.py) — change the constant and this section together. The response schema is [`EdgeCoreRestartResponseSchema`](/api-reference/rest/EdgeCoreRestartResponseSchema). Note that `alert_uuid` is `null` when no environment can be resolved for the edge (typically: no bound twin yet); the restart still happens, just untracked. ## Frontend display contract **Read this before adding a new `alert_type`.** Every alert that the backend or an edge driver can raise must either render correctly with the generic alert card, or have a documented specialised renderer linked from this section. Skipping this step is how we end up with overlapping alert types that nobody can untangle six months later. The workbench renders every alert through a single `AlertCard` ([`cyberwave-frontend/components/alerts/alert.tsx`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-frontend/components/alerts/alert.tsx)). The generic path uses **only** these fields and needs nothing else from the producer: | Field | Display | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `severity` | Left border colour + leading icon (`info` / `warning` / `error` / `critical` — see [`alert-display.ts`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-frontend/components/alerts/alert-display.ts)) | | `status` | Status pill (`Active` / `Acknowledged` / `Resolved` / `Silenced`). `resolved` and `silenced` also dim the card to 60% opacity. | | `source_type` | Small outline badge | | `alert_type` | Small mono-font outline badge — this is what tells the operator which producer raised the alert, so make it specific and stable. | | `name` | Card title | | `description` | Body text. URLs are auto-linked. | | `media` | Inline image (`.png`/`.gif`) or autoplaying muted video (`.mp4`). | | `created_at` | Relative timestamp with absolute on hover. | | `metadata.buttons` | Generic action buttons that publish back on `cyberwave/twin/{twin_uuid}/command` as a `button` command. | The new `edge_core_restart` alert deliberately uses **only** the generic path. The lifecycle is encoded in `metadata.phase`, so any UI that wants to surface "Restart in progress vs. completed vs. failed" can read that field without a dedicated component, and the audit trail (`request_id`, `pre_resolved_alert_uuids`, `previous_phase`, `timed_out_at`) is plain JSON. Specialised renderers exist for a handful of historical alert types that need bespoke interactions; each one is a known cost, not a pattern to copy: | `alert_type` | Specialised behaviour | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `robot_setup` | Spinner replaces the severity icon while `status` is `active` / `acknowledged` | | `robot_setup_done` | Green success panel with a check mark and amber/green accent | | `calibration_needed` | Inline `Next` / `Complete` / `Restart calibration` actions that publish to `cyberwave/twin/{twin_uuid}/command` instead of using metadata buttons | | `camera_default_device` | `Default is fine` action that writes the chosen device into twin metadata and resolves the alert | | `driver_starting` | Phase-aware spinner with rewritten copy (`Downloading driver image…` / `Installing driver image…` / `Starting driver container…`) driven by `metadata.phase`, plus a byte/percent suffix when the pull is mid-flight — see [`driver_starting` progress metadata](#driver_starting-progress-metadata) | ### Adding a new `alert_type` Before you introduce a new `alert_type`: 1. **Check this page.** If an existing type fits — even loosely — extend its `metadata` instead of forking a new code. 2. **Default to the generic path.** Pick a sensible `severity`, write a clear `name` + `description`, and put any structured state on `metadata`. The generic card will render it correctly. 3. **Only add a specialised renderer when the interaction itself is novel** (e.g. a calibration step that needs custom MQTT commands). Generic `metadata.buttons` cover most operator-confirms-something flows without new code. 4. **Document the type in this page** before merging — both the catalog row above and, if specialised, the table in this section. A new `alert_type` constant that does not have a row here should not pass review. ### `driver_starting` progress metadata Edge-core writes `docker pull` progress directly onto the active `driver_starting` alert's `metadata`, so the workbench renders a live `"Downloading driver image (cyberwaveos/ugv-driver:dev) — 745 MB of 1.55 GB (47%)"` line without any extra round-trip. The fields are: | Field | Type | Meaning | | ---------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `phase` | string | Lifecycle marker. Pull walks `pull_started → downloading → installing → pull_complete → pull_stream_finished`, then `starting_container → container_created → container_running` once the container is up. Failure phases are `pull_spawn_failed` / `pull_timed_out` / `pull_exit_error`. | | `image` | string | The driver image being pulled. | | `progress_percent` | int (0–100) | Integer percent of `layers_fetched / layers_total` — docker declares a layer's size only once it starts fetching it, so a byte ratio has an unknown denominator for most of a pull. Capped at `99` until docker confirms the pull finished; `100` at `pull_complete`. | | `overall_progress_percent` | int (0–100) | The whole startup as one number that only moves forward: download, install and container start each get a band of it. This is what a progress bar should read. | | `stage_progress_percent` | int (0–100) | The same startup expressed *per stage*, each restarting at 0. Use it only alongside something that names the current stage. | | `downloaded_bytes` / `total_bytes` | int | Raw byte totals aggregated across all layers. `total_bytes` is a partial sum while `total_bytes_partial` is `true`. | | `total_bytes_partial` | bool | `true` while any announced layer has not yet declared its size, i.e. `total_bytes` is not the image's size. | | `layers_fetched` | float | Layers whose bytes are on disk, the layer currently downloading counted as its byte fraction. Numerator of `progress_percent`. | | `downloaded_human` / `total_human` | string \| null | Same values rendered in SI units (`"745 MB"`, `"1.55 GB"`). `total_human` is `null` whenever `total_bytes_partial` is `true`, so a partial sum is never rendered as a hard "of Y"; `downloaded_human` is `null` before docker emits any byte-bar. | | `layers_total` / `layers_complete` | int | Number of layers seen so far and number with `Pull complete`. Drives the caption and the percentage through the `installing` phase, which on a multi-GB image outlasts the download. | | `layers_active` | int | Layers currently in flight (downloading, verifying or extracting). | | `last_docker_pull_line` | string | Most recent raw `docker pull` line (truncated to 500 chars), kept for debugging. | The frontend renderer is in [`cyberwave-frontend/components/alerts/alert.tsx`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-frontend/components/alerts/alert.tsx) — search for `getDriverStartingDisplayText`. ## MQTT Edge devices create and resolve alerts via MQTT. Topic pattern: ```text theme={null} cyberwave/twin/{twin_uuid}/alert ``` # BaseDriver (Python SDK) Source: https://docs.cyberwave.com/feature-reference/edge/drivers/base-driver-class Reference for cyberwave.driver.BaseDriver — what the SDK runs automatically, what you must implement, lifecycle, registry, alerts, and manifests. ## What `BaseDriver` is `BaseDriver` (`cyberwave.driver`) is the **template-method lifecycle shell** for Python edge drivers. You declare the platform contract once in **`define_interface()`**; the SDK compiles it to `metadata["mqtt"]` (and optional `metadata["zenoh"]`), wires MQTT at runtime, and runs a fixed async lifecycle. | Concern | Who owns it | | ----------------------------------------------------- | ---------------------------------------------- | | Cyberwave API + MQTT connect, twin binding | **SDK** (`_connect_cloud_async`) | | Session markers (`telemetry_start`, `connected`, …) | **SDK** | | Interface registry → subscribe/publish | **SDK** (`_wire_interface_from_registry`) | | Default management commands (`stop`, teleop modes, …) | **SDK** (`define_interface_defaults`) | | Debounced `driver_info` on `twin/telemetry` | **SDK** (`BaseTelemetry`) | | Lifecycle + active alerts (local + twin UI) | **SDK** (`_transition_to`, `AlertManager`) | | Device I/O (serial, camera SDK, custom protocol) | **You** (`on_connect_to_device`, callbacks, …) | Do **not** override `run_async()`. Override hooks and `define_interface()` instead. For ROS 2 robots, use **[BaseROS2Driver](/feature-reference/edge/drivers/ros2-base-driver)** instead — it subclasses `BaseDriver` and adds rclpy lifecycle + `from_ros` forwarding. *** ## Construction ### Recommended (notebook, tests, explicit twin) ```python theme={null} from cyberwave import Cyberwave from my_driver import MyDriver cw = Cyberwave(api_key="...") twin = cw.twin("acme-corp/my-arm", twin_id="...") twin.driver.set_schema(MyDriver.get_manifest()) # before run — aligns twin.commands MyDriver(twin=twin).run() # blocking; asyncio.run(run_async()) ``` ### Edge Core / Docker (env-driven) Edge Core injects `CYBERWAVE_TWIN_UUID`, `CYBERWAVE_API_KEY`, MQTT settings, etc. The driver typically uses: ```python theme={null} class MyDriver(BaseDriver): @classmethod def create(cls) -> BaseDriver: return cls.from_env() # or parse argv → Params if __name__ == "__main__": MyDriver.create_and_run_async() # asyncio entrypoint ``` `from_env()` calls `Params.from_env()` when your subclass defines `Params`; otherwise `cls(None)` and twin UUID comes from **`CYBERWAVE_TWIN_UUID`** during cloud connect. ### Constructor kwargs | Argument | Effect | | ------------------------------- | ------------------------------------------------------------------------------------ | | `params` | Opaque config object (your `Params` dataclass, CLI args, …) | | `twin=` | Pre-bound twin — skips fetch; uses `twin.client` for MQTT | | `client=` | Pre-bound `Cyberwave` client (rare; usually via `twin`) | | `auto_register_interface=False` | Skips `register_interface_on_twin()` after connect (you called `set_schema` already) | On `__init__`, the SDK always: 1. Creates `DriverInterfaceRegistry`, `AlertManager`, `BaseTelemetry` 2. Calls **`define_interface_defaults(iface)`** (built-in commands + telemetry publisher) 3. Calls **`define_interface(iface)`** (your declarations) *** ## Required vs optional (checklist) ### You must implement (abstract) | Method | Cyberwave state when called | Purpose | | ------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | `on_configure()` | `CONFIGURING` (after MQTT + twin ready) | Load config, open files, build objects that do **not** need live hardware | | `on_connect_to_device()` | `CONNECTING` | Open transport: serial, WebRTC, vendor SDK, ROS bridge client, … | | `on_register_callbacks()` | `INACTIVE` (device already connected) | **Device-native** subscriptions only — camera frame callback, serial read loop, **not** MQTT registry | | `on_activate()` | `INACTIVE` (after `_wire_interface_from_registry`) | Start streams/controllers; driver becomes operational before ACTIVE tick loop | | `on_shutdown()` | `finally` of `run_async` (always) | Idempotent cleanup — close handles, stop threads | | `create()` | N/A (classmethod) | Only if entrypoint is `create_and_run_async()` — parse env/CLI and return `cls(...)` | Pure forward-only ROS drivers often leave the four async `on_*` hooks as no-ops on **`BaseROS2Driver`** (see ROS page); on plain **`BaseDriver`** they are still abstract and must exist (can `pass`). ### You usually implement | Piece | Required? | Notes | | ------------------------- | ------------------------------ | ----------------------------------------------------------------------------- | | `define_interface(iface)` | Yes for custom topics/commands | Empty body OK if defaults suffice (unusual) | | Command callbacks | Per `add_listener` | Sync or async; registry dispatches on driver asyncio loop | | Publisher callbacks | Per tick-based `add_publisher` | Return `dict` each tick at `PublisherArgs.rate_hz` | | `REGISTRY_ID` | Strongly recommended | Catalog key + manifest `asset_key`; enables auto `register_interface_on_twin` | ### Optional overrides (defaults are fine) | Method / attribute | Default behavior | | --------------------------- | ------------------------------------------------------------------------------------------ | | `on_tick()` | No-op; runs at `TICK_RATE_HZ` after registry publishers | | `on_start_monitoring()` | Waits until shutdown (no extra task) | | `on_reconnect()` | Returns `False` → no transport reconnect | | `driver_info_extra()` | Extra fields merged into telemetry snapshots | | Cloud connect | `Cyberwave(source_type="edge")` — uses `CyberwaveConfig` / `CYBERWAVE_*` env (same as CLI) | | `TICK_RATE_HZ` | `10.0` Hz | | `TELEMETRY_PUBLISH_RATE_HZ` | `1.0` Hz for built-in `twin/telemetry` publisher | | `auto_register_interface` | `True` | | `driver_family` | `"python"` | *** ## Full lifecycle (`run_async`) ```mermaid theme={null} sequenceDiagram participant Main participant BaseDriver participant Cloud as Cyberwave API/MQTT participant Device Main->>BaseDriver: run() / run_async() BaseDriver->>BaseDriver: CONFIGURING BaseDriver->>Cloud: _connect_cloud_async() BaseDriver->>Cloud: telemetry_start, connected opt auto_register_interface + REGISTRY_ID BaseDriver->>Cloud: register_interface_on_twin() end BaseDriver->>BaseDriver: on_configure() BaseDriver->>BaseDriver: CONNECTING BaseDriver->>Device: on_connect_to_device() BaseDriver->>BaseDriver: INACTIVE BaseDriver->>Device: on_register_callbacks() BaseDriver->>Cloud: _wire_interface_from_registry() BaseDriver->>BaseDriver: on_activate() BaseDriver->>BaseDriver: _activate_registry_zenoh() BaseDriver->>BaseDriver: ACTIVE BaseDriver->>Cloud: _derive_initial_operation_mode() (controller → mode) par Tick loop BaseDriver->>BaseDriver: _run_registry_publishers + on_tick and Monitoring BaseDriver->>BaseDriver: on_start_monitoring and Reconnect watcher BaseDriver->>BaseDriver: _reconnect_loop_async end Main->>BaseDriver: request_shutdown / SIGINT BaseDriver->>BaseDriver: DEACTIVATING BaseDriver->>Cloud: _unwire_interface_from_registry BaseDriver->>Cloud: telemetry_end, disconnected BaseDriver->>BaseDriver: on_shutdown() BaseDriver->>BaseDriver: FINALIZED ``` ### Step-by-step (what happens without your code) 1. **`CONFIGURING`** — Log `[STATE] unconfigured → configuring`. Raise lifecycle alert + twin notice *"Driver starting"*. 2. **`_connect_cloud_async()`** — `Cyberwave(source_type="edge")` (SDK defaults + `CYBERWAVE_*` env). Connect MQTT. Resolve twin: reuse `twin=` or fetch by `robot_uuid` / asset. 3. **`_start_driver_telemetry_session()`** — Publish `telemetry_start` + `connected` on MQTT; start debounced `driver_info` via `BaseTelemetry`. 4. **`register_interface_on_twin()`** — If `auto_register_interface` and class `REGISTRY_ID` are set: `twin.driver.set_schema(self.manifest)` (failures are logged, driver continues). 5. **`on_configure()`** — Your hook. 6. **`CONNECTING`** — Twin notice *"Driver connecting to device"*. **`on_connect_to_device()`**. 7. **`INACTIVE`** — Notice *"Driver wiring interfaces"*. **`on_register_callbacks()`** then **`_wire_interface_from_registry()`**: * Subscribes MQTT listeners for `add_listener` entries (respecting `operation_modes`) * Schedules tick publishers for `add_publisher` entries with `PublisherArgs.rate_hz` * Does **not** subscribe ROS topics (use `BaseROS2Driver` + `from_ros`) 8. **`on_activate()`** then **`_activate_registry_zenoh()`** — Opens edge `DataBus` for dual/Zenoh specs. 9. **`ACTIVE`** — Notice *"Driver active"* + `DRIVER_ACTIVE` alert. Then **`_derive_initial_operation_mode()`** sets the starting mode from the twin's attached controller (see [Operation modes](#operation-modes-driveroperationmode)), and `asyncio.gather(_tick_loop_async, on_start_monitoring, _reconnect_loop_async)`. 10. **Shutdown** — `request_shutdown()` sets `_shutdown` event. Unwire MQTT, end telemetry session, `on_shutdown()`, flush `AlertManager`, **`FINALIZED`**. On unhandled exceptions: state **`ERROR`**, then same `finally` teardown. *** ## Lifecycle states (`DriverLifecycleState`) | State | Meaning | Twin notice (when twin bound) | | -------------- | ------------------------------- | ----------------------------- | | `unconfigured` | Before `run()` | — | | `configuring` | Cloud connect + `on_configure` | Driver starting | | `connecting` | `on_connect_to_device` | Driver connecting to device | | `inactive` | Registry wiring + `on_activate` | Driver wiring interfaces | | `active` | Tick loop running | Driver active | | `reconnecting` | MQTT reconnect attempts | Driver reconnecting (warning) | | `deactivating` | Teardown started | Driver shutting down | | `finalized` | Process exiting | Driver stopped | | `error` | Failure before/during teardown | Driver error | Each transition: * Logs `INFO [STATE] from → to` * Updates debounced **`driver_info`** (`lifecycle_state` field) * Raises **`DRIVER_LIFECYCLE`** via `AlertManager` (resolved on next transition) * On **`active`**: also raises **`DRIVER_ACTIVE`** (resolved on deactivate/finalize/error) * Calls **`create_twin_alert`** for the UI when `_twin` is available (queued if twin not ready yet, flushed after connect) Backend alert integration is **always enabled** after MQTT connect (not configurable). *** ## `define_interface` and the registry ### Call order at import/construction ```text theme={null} define_interface_defaults(iface) # SDK — do not override unless you know why define_interface(iface) # your driver class body ``` ### What `define_interface_defaults` registers | Entry | MQTT topic | Role | | ---------------------------- | --------------------------------- | ------------------------------------------------------------------------ | | Command `stop` | `cyberwave/twin/{uuid}/command` | Stop motion / safe state | | Command `teleoperate` | same | Enter local teleop mode | | Command `remoteoperate` | same | Enter remote teleop mode | | Command `controller-changed` | same | Controller identity updates | | Publisher `twin/telemetry` | `cyberwave/twin/{uuid}/telemetry` | Debounced **`driver_info`** @ `TELEMETRY_PUBLISH_RATE_HZ` (default 1 Hz) | Handlers are wired to internal methods (`_on_stop_cmd`, …) that update **`operation_mode`** and re-wire listeners when modes change. ### Declaring your own entries ```python theme={null} from cyberwave.driver import ( CallbackGroup, CommandArgs, TopicSpec, PublisherArgs, DriverOperationMode, ) def define_interface(self, iface): iface.add_listener( TopicSpec(topic_slug="cyberwave/twin/{twin_uuid}/command"), CallbackGroup(callback=self._on_rotate), command=CommandArgs(name="rotate", continuous=False), operation_modes=frozenset({DriverOperationMode.TELEOP_LOCAL, DriverOperationMode.TELEOP_REMOTE}), ) iface.add_publisher( TopicSpec(namespace="twin", leaf="imu", payload_schema_ref="ImuPayload"), CallbackGroup(callback=self._sample_imu), publisher=PublisherArgs(rate_hz=50.0), ) ``` | API | Direction | You supply | | -------------------------------- | ----------------------------------- | -------------------------------------------------------------------- | | `add_listener` | Cyberwave → driver (MQTT in) | `CallbackGroup(callback=…)`, optional `CommandArgs` | | `add_publisher` | Driver → Cyberwave (MQTT/Zenoh out) | `CallbackGroup` returning `dict` **or** empty group + tick `rate_hz` | | `add_publisher(..., from_ros=…)` | — | **Only on `BaseROS2Driver`** — see ROS page | **`on_register_callbacks` is not for MQTT.** Registry wiring happens in `_wire_interface_from_registry()` after your hook returns. Use `on_register_callbacks` for hardware/SDK subscriptions only. **`twin/command` must stay MQTT.** Do not set `enable_zenoh=True` on command listeners. ### Command parameters In a supporting SDK release, declare the values a user must provide with a command: ```python theme={null} from cyberwave.driver import CommandArg, CommandArgs gripper_command = CommandArgs( name="gripper", description="Control the configured gripper", args=(CommandArg( "action", type="string", required=True, enum=("grip", "release", "reset"), ),), ) ``` Pass this declaration to your existing listener. Keyboard setup in Catalog and Workbench shows the declared choices. Commands with missing required values remain available for configuration, without receiving an automatic key binding. Validate hardware limits and the command itself in your driver before executing it. The original `CommandArg(name, default, unit)` form keeps its existing behavior. Typed fields are optional and keyword-only; `min_items` declares a minimum array length. Numeric zero and boolean false defaults are retained. Adopt typed declarations deliberately with a compatible backend; declaring parameters does not make a device ready to move. After refreshing the twin, inspect its current commands before changing an existing typed declaration. Save the revision you reviewed and pass it with the update: ```python theme={null} twin.refresh() current_commands = twin.driver.get_command_specs() revision = twin.driver.get_revision() # Review current_commands and your replacement before applying it. twin.driver.set_schema("cw-driver.yml", expected_revision=revision) ``` If the update returns `409`, refresh and review again. Do not automatically retry a changed configuration. Existing untyped declarations keep their current behavior. ### Operation modes (`DriverOperationMode`) Orthogonal to lifecycle state — gates which `add_listener` / `add_publisher` entries are active. An entry is wired only when the driver's current mode is in its `operation_modes` set. | Mode | Value | Typical use | | --------------- | --------------- | ------------------------------------------------------- | | `NO_OP` | `no_op` | Safe / idle — no controller assigned; commands disabled | | `TELEOP_LOCAL` | `teleop_local` | Operator at the robot (`localop` controller) | | `TELEOP_REMOTE` | `teleop_remote` | Remote operator (any other controller type) | **Initial mode is derived from the twin's attached controller**, not hard-coded. At the end of startup (just after `ACTIVE`), `run_async` calls `_derive_initial_operation_mode()`, which re-fetches the twin from the API (`refresh_driver_twin_from_api`) and reads its attached controller policy (`resolve_twin_attached_controller`): | Twin controller at startup | Resulting mode | | ------------------------------ | --------------------------------- | | none assigned | `NO_OP` (the constructor default) | | `controller_type == "localop"` | `TELEOP_LOCAL` | | any other controller type | `TELEOP_REMOTE` | When a controller is resolved, the driver calls **`on_controller_assigned(ctype, policy_uuid)`** (override to add driver-specific alerts/setup). **Runtime switches** come through the default management commands (`controller-changed`, `teleoperate`, `remoteoperate`, `stop`). Each routes to `_set_operation_mode(mode)`, which — only when the mode actually changes — re-wires the interface registry (and ROS `from_ros` forwarders), then calls the matching enter hook and emits a `driver_info` update with the new `operation_mode`: | Hook | Called when | | ------------------------------------------------------ | ------------------------------------------------- | | `on_enter_no_op()` | entering `NO_OP` | | `on_enter_teleop_local()` | entering `TELEOP_LOCAL` | | `on_enter_teleop_remote()` | entering `TELEOP_REMOTE` | | `on_exit_operation()` | leaving any mode (before the new mode is applied) | | `on_controller_assigned()` / `on_controller_removed()` | controller attached / detached | Read the live mode via the **`operation_mode`** property. Because `_set_operation_mode` is a no-op when the mode is unchanged, a forward-only driver with no controller stays in its initial `NO_OP` and never fires an enter hook — declare such publishers with `operation_modes=frozenset(DriverOperationMode)` so they stream in every mode. *** ## Stream publish rate limiting High-frequency sources (sensor topics, IMUs) can exceed 100–200 Hz; publishing every sample to MQTT/Zenoh overloads the broker. `BaseDriver` provides a per-stream monotonic throttle: | API | Purpose | | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `STREAM_PUBLISH_MAX_HZ` | Class attribute, default **30 Hz** — the cap applied to throttled streams | | `stream_publish_max_hz(stream_key)` | Resolves the effective cap for `stream_key` (see resolution order below) | | `acquire_stream_publish_slot(stream_key, *, max_hz=None)` | Returns `True` when a publish on `stream_key` is due (latest-wins; drops samples that arrive faster than the cap) | ```python theme={null} def _on_sensor_sample(self, sample) -> None: if not self.acquire_stream_publish_slot("imu"): return # too soon since last publish — drop this sample self._publish(sample) ``` **Resolution order** for the effective cap (highest wins): a per-publisher `TopicSpec(rate_hz=...)` on the `from_ros`/`add_publisher` entry → the node manifest's top-level `mqtt_max_hz:` value → the `STREAM_PUBLISH_MAX_HZ` class default. No environment variable controls this. Tick-based registry publishers are already paced by `PublisherArgs.rate_hz`; this throttle is for callback-driven streams you publish yourself. `BaseROS2Driver` adds a ROS-topic-aware wrapper — see the ROS page. *** ## Source-type convention Every state payload on the Cyberwave bus carries a **`source_type`** that says *who produced it*. This is how the platform keeps a driver's own feedback from being mistaken for a command (and vice versa). The basic contract for a driver is simple: > **Publish your state as `edge` (or `sim`). Listen for teleop commands (`tele`, `edit`, `sim_tele`).** | `source_type` | Produced by | A driver should | | -------------------------------------- | ---------------------------------------------- | -------------------------------------------------------- | | `edge`, `edge_leader`, `edge_follower` | The driver itself — physical hardware feedback | **Publish** these; **never act on** them inbound | | `sim` | A simulator standing in for hardware | **Publish** instead of `edge` when running in simulation | | `tele` | Live teleoperation | **Listen** and actuate | | `edit` | Manual pose editing in the UI | **Listen** (allowed command source) | | `sim_tele` | Teleop targeting a simulated twin | **Listen** (allowed command source) | ### Publishing (outbound) Tag outbound state with `edge` by default, or `sim` when the driver is driving a simulator rather than hardware. For `from_ros` publishers the SDK stamps `edge` for you (see the [ROS page](/feature-reference/edge/drivers/ros2-base-driver#source-type-convention)); for hand-built publisher callbacks, include `"source_type": SOURCE_TYPE_EDGE` in the returned dict. ### Listening (inbound) Declare the command source types a listener accepts with `ProtocolArgs`: ```python theme={null} from cyberwave.constants import SOURCE_TYPE_EDGE from cyberwave.driver import CallbackGroup, DriverOperationMode, ProtocolArgs, TopicSpec iface.add_listener( TopicSpec(namespace="joint", leaf="update", payload_schema_ref="JointUpdatePayload"), CallbackGroup(callback=self._on_joint_cmd), protocol=ProtocolArgs(source_types=["tele", "edit", "sim_tele"]), operation_modes=frozenset({DriverOperationMode.TELEOP_LOCAL, DriverOperationMode.TELEOP_REMOTE}), ) ``` The acceptance rule a listener should apply to each inbound message: | Inbound `source_type` | Behavior | | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | | in the listener's allowed set (`tele` / `edit` / `sim_tele`) | **accept** | | **absent / `None`** | **accept** — *relaxed*: not every producer stamps the field, so untagged messages are treated as commands | | `edge`, `edge_leader`, `edge_follower` | **reject** — never actuate on your own feedback (this guard holds even for the relaxed/untagged case) | | present but not in the allowed set | reject | **The `edge*` self-echo guard is the one rule you cannot relax.** When the *same* topic is both an `edge` publisher and a `tele` listener — common for an arm's `joint/update` — accepting `edge` inbound would feed the driver its own joint feedback as a command and the arm would fight itself. *** ## What the tick loop does During **ACTIVE**, `_tick_loop_async` runs at **`TICK_RATE_HZ`** (class attribute, default **10 Hz**): 1. **`_run_registry_publishers()`** — For each publisher with `PublisherArgs.rate_hz`, if the tick counter matches the rate, invoke callback and publish to MQTT and/or Zenoh (when `enable_zenoh=True`). 2. **`on_tick()`** — Your extra periodic work. `from_ros` publishers **do not** use this loop — ROS message rate drives publishing (ROS driver only). *** ## Identity: twin, asset, environment | Property | Source | | ----------------- | ---------------------------------------------------------- | | `robot_uuid` | `twin.uuid`, or `CYBERWAVE_TWIN_UUID` | | `asset_key` | Class **`REGISTRY_ID`** on your driver subclass (required) | | `env_uuid` | Twin’s environment (after connect) | | `client` / `twin` | After `_connect_cloud_async` — raises if accessed early | *** ## Manifest export (no `run()`) | API | Returns | Use | | --------------------------------------------- | ---------------------------------- | ------------------------------------------ | | `MyDriver.get_manifest()` | Compiled `metadata["mqtt"]` bundle | `twin.driver.set_schema(...)` | | `MyDriver.get_manifest_bundles()` | `{mqtt, zenoh?}` | Dual-transport twins | | `MyDriver.get_manifest(path="cw-driver.yml")` | Same + writes YAML | Docker `COPY`, asset seeding | | `MyDriver.get_manifest(compiled=False)` | Raw `cw-driver.yml` dict | Inspection | | `driver.manifest` | Instance shortcut | Same as `get_manifest()` on running driver | | `driver.register_interface_on_twin()` | — | `set_schema` on bound twin | Compiled bundles include top-level **`asset_key`** from `REGISTRY_ID`. Probe instances use `_manifest_probe()` — no MQTT, no lifecycle. *** ## Environment variables (cloud shell) Loaded by `CyberwaveConfig` when the driver calls `Cyberwave(source_type="edge")` (same as the rest of the SDK): | Variable | Default / notes | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `CYBERWAVE_API_KEY` | Required for connect (or pre-bound `twin.client`) | | `CYBERWAVE_TWIN_UUID` | Twin when not passing `twin=` | | `CYBERWAVE_BASE_URL` | `https://api.cyberwave.com` | | `CYBERWAVE_MQTT_HOST` | `mqtt.cyberwave.com` | | `CYBERWAVE_MQTT_PORT` | `8883` | | `CYBERWAVE_MQTT_USE_TLS` | `true` when port is 8883 | | `CYBERWAVE_MQTT_USERNAME` | Broker username. Leave unset: the SDK derives one from your API key so the broker can identify the session. Set it only for legacy broker accounts. | | Edge Core also sets twin JSON path, child twin UUIDs, restart tuning — see [Writing compatible drivers](/feature-reference/edge/drivers/writing-compatible-drivers#environment-variables). | | *** ## Alerts and operator visibility | API | When to use | | ----------------------------------- | ----------------------------------------------------------------------- | | `create_twin_alert(name, …)` | Notices that must appear on the twin in the UI (lifecycle is automatic) | | `raise_alert` / `raise_alert_async` | Structured alerts via `AlertManager` | | `resolve_alert(component, code)` | Clear a prior alert | `create_twin_alert` from the asyncio loop dispatches HTTP in a **background thread** so ticks are not blocked. *** ## Edge health (twin liveness) `BaseDriver` automatically starts an `EdgeHealthCheck` publisher on `cyberwave/twin/{uuid}/edge_health` right after the MQTT interface is wired, and stops it on shutdown — no lifecycle wiring required. | API | Purpose | | ----------------------- | ------------------------------------------------------------------------------------------------- | | `edge_health_extras()` | Override to merge driver-specific fields into every heartbeat (default `{}`) | | `edge_health_streams()` | Override to return `[(stream_id, stream_config), ...]` registered on the publisher (default `[]`) | | `_touch_edge_health()` | Call from a data-received callback to mark the stream alive | ```python theme={null} def edge_health_extras(self) -> dict: return {"ctrl_mode": self._ctrl_mode} def edge_health_streams(self): return [("arm-joints", {"kind": "imu", "source": "joint_states", "rate_hz": 10})] ``` `cyberwave-edge-core` also runs its own `EdgeHealthCheck` per linked twin for host-level metrics (memory, CPU temp, watchdog). A driver container's `edge_health_extras()` is a stopgap reuse of the same publish mechanism for driver-specific fields — a dedicated per-driver telemetry channel is planned to replace it. *** ## MQTT reconnect If **`RECONNECT_MAX_ATTEMPTS`** > 0 (default **5**) and you override **`on_reconnect()`** to return `True` when transport is restored, `_reconnect_loop_async` reacts to **`_connection_lost`** (set this from your device code on disconnect). Default **`on_reconnect`** returns `False` — reconnect is effectively off; repeated failures can move to **`ERROR`**. Set **`RECONNECT_MAX_ATTEMPTS=0`** to disable the watcher entirely. *** ## Zenoh (edge-colocated) Opt in per publisher via `TopicSpec` fields: ```python theme={null} TopicSpec( topic_slug="cyberwave/twin/{twin_uuid}/imu", payload_schema_ref="ImuPayload", enable_zenoh=True, zenoh_channel="imu", ) ``` At **`on_activate`**, `_activate_registry_zenoh()` opens **`data_bus_for(twin_uuid)`** and publishes registry streams locally. High-rate binary (camera) often uses **`ZenohPublisherMixin`** instead of tick publishers. *** ## Class attributes reference ```python theme={null} class MyDriver(BaseDriver): REGISTRY_ID = "acme-corp/my-device" # manifest + auto register driver_family = "python" # cw-driver metadata TICK_RATE_HZ = 50.0 # on_tick + publisher scheduling base TELEMETRY_PUBLISH_RATE_HZ = 1.0 # built-in twin/telemetry publisher STREAM_PUBLISH_MAX_HZ = 30.0 # cap for acquire_stream_publish_slot() auto_register_interface = True # False if set_schema before run() RECONNECT_MAX_ATTEMPTS = 5 RECONNECT_BACKOFF_BASE = 2.0 RECONNECT_BACKOFF_MAX = 60.0 ``` *** ## Anti-patterns | Don't | Do instead | | --------------------------------------------------------------- | ---------------------------------------------------------------- | | Override `run_async()` | Override hooks | | Subscribe `twin/command` manually | `add_listener` + `CommandArgs` | | Call `mqtt.publish` for registry topics | Publisher callback or `from_ros` | | Put ROS subscriptions in `on_register_callbacks` on ROS drivers | `from_ros=` or `register_callbacks()` on `BaseROS2Driver` | | Skip `set_schema` when `auto_register_interface=False` | `twin.driver.set_schema(MyDriver.get_manifest())` before `run()` | | Block for seconds inside `on_tick` | Offload to threads/tasks; keep tick fast | *** ## Related rclpy lifecycle, `from_ros`, UR Sim lab. Platform contract, `cw-driver.yml`, tutorials. Alert codes and operator surfaces. # Camera detection overlays Source: https://docs.cyberwave.com/feature-reference/edge/drivers/camera-detection-overlays Draw YOLO bounding boxes from an ML worker onto the camera driver's WebRTC stream. The generic `cyberwave-edge-camera-driver` subscribes to detection results published by any ML worker on the same Zenoh router and renders bounding boxes + labels on the WebRTC stream before it reaches the frontend. No client-side changes are required. ## How it works * Frames captured from the camera are published **clean** on `cw//data/frames/` — ML workers always receive unannotated images. * The driver also subscribes to `cw//data/detections/**`. Any worker that publishes detections on that channel (e.g. `detections/ultralytics`, `detections/onnxruntime`) drives the overlay. * Bounding boxes are drawn in-place on the capture ndarray before it is handed to the WebRTC encoder, so the browser sees annotated frames without any extra infrastructure. * Workers publish every inference — including empty `{"detections": []}` heartbeats — so the driver's freshness timer is kept alive between non-empty frames. Batches older than 2 seconds are discarded to avoid stale overlays. ## Detection payload schema ```json theme={null} { "detections": [ {"label": "person", "confidence": 0.92, "x1": 120, "y1": 80, "x2": 340, "y2": 620} ], "frame_width": 1920, "frame_height": 1080 } ``` Coordinates are in pixel space of the detection frame. The driver rescales them to the capture resolution. ## Configuration | Variable | Default | Description | | ------------------------------ | ------- | -------------------------------------------------- | | `CYBERWAVE_DETECTION_OVERLAYS` | `true` | Set to `false` to disable overlays on RGB cameras. | Overlays are disabled automatically for twins that declare a depth sensor in their capabilities. ## Interop with native drivers The same channel, payload schema, and staleness policy are used by the C++ OBSBOT driver, so an ML worker only needs to publish once — both driver families render the results identically. # Camera driver: hardware H.264 encoding Source: https://docs.cyberwave.com/feature-reference/edge/drivers/camera-hardware-h264-encoding Hardware-accelerated H264 encoding for edge video streaming, with automatic software fallback. Cyberwave edge video streaming auto-detects a usable hardware H264 encoder at stream start and falls back to software encoding (`libx264`) when none is available. | Platform | Hardware encode | Notes | | -------------------- | --------------- | ----------------------------------------------- | | Raspberry Pi 4 | ✓ | pass `--device /dev/video11` to the container | | Raspberry Pi 5 | ✗ | no H264 encode silicon — software fallback | | Jetson Orin NX / AGX | ✓ | jetson image variant + NVIDIA container runtime | | Jetson Orin Nano | ✗ | no encode silicon — software fallback | | amd64 | ✗ (planned) | software fallback today | ## Configuration Set `CYBERWAVE_VIDEO_ENCODER` to `auto` (default), a specific encoder name (e.g. `h264_v4l2m2m`), or `libx264` to force software encoding. The active encoder is visible in the WebRTC offer's stream attributes (`video_encoder`). See the public README at [`cyberwave-edge-camera-driver`](https://github.com/cyberwave-os/cyberwave-edge-camera-driver) for the full configuration matrix. # Camera driver: V4L2 backend requirement Source: https://docs.cyberwave.com/feature-reference/edge/drivers/camera-v4l2-backend Why the Linux camera-driver container ships with apt python3-opencv instead of the opencv-python wheel, and what to do if you hit a 5 fps YUYV stream. The `cyberwaveos/camera-driver` image installs OpenCV via Debian's `python3-opencv` package, not the `opencv-python` PyPI wheel. The Debian package is built with the native V4L2 backend (`V4L/V4L2: YES` in `cv2.getBuildInformation()`); the manylinux PyPI wheel is not. Without V4L2, `cv2.VideoCapture("/dev/video0")` routes through FFmpeg's libavformat V4L2 demuxer. There `cap.set(CAP_PROP_FOURCC, MJPG)` is silently ignored, so the camera falls back to its kernel default — typically YUYV 1920×1080 at 5 fps over USB 2.0. The stream looks "up" but pushes \~58 MB/s of raw frames and blows every downstream worker's frame budget. ## Self-test `CV2VideoTrack.__init__` calls `cv2.getBuildInformation()` on Linux startup and raises `RuntimeError` if the `V4L/V4L2: YES` row is missing. The same assertion runs at Docker build time so a future packaging accident fails CI rather than production. Set `CYBERWAVE_CAMERA_SKIP_V4L2_CHECK=1` to bypass the SDK check intentionally. ## Strict geometry Set `CYBERWAVE_CAMERA_STRICT_GEOMETRY=1` to escalate a resolution mismatch (e.g. requested VGA, got 1080p) from a `WARNING` to a `RuntimeError`. Off by default because some cameras legitimately round to the nearest supported mode. ## Platform support | Scenario | Path | | -------------------- | -------------------------------------------------------------------------------------------- | | Linux edge (Pi, x86) | `cyberwaveos/camera-driver` | | macOS native | `pip install cyberwave[camera]` (uses AVFoundation) | | Windows native | `pip install cyberwave[camera]` (uses MSMF / DSHOW) | | Docker on macOS | Not supported — Docker Desktop's LinuxKit VM does not expose host USB devices to containers. | See the public README at [`cyberwave-edge-camera-driver`](https://github.com/cyberwave-os/cyberwave-edge-camera-driver) for the full configuration matrix. # Data fusion primitives Source: https://docs.cyberwave.com/feature-reference/edge/drivers/data-fusion Time-aware sensor fusion: interpolated point reads and time-window queries for multi-sensor edge workers. `cyberwave.data.FusionLayer` provides time-aware fusion primitives for edge workers that fuse multiple sensor streams. `cw.data` (the data bus) does not expose them yet: create a `FusionLayer` and feed it with `ingest()`. ## `data.at()` — Interpolated point read Query a channel at an arbitrary timestamp. The SDK interpolates between the two nearest buffered samples. Returns `None` for unknown channels. When `t` falls outside the buffered range, the nearest boundary sample is returned (constant extrapolation). ```python theme={null} from cyberwave.data import FusionLayer fusion = FusionLayer() # feed it: fusion.ingest("joint_states", ts, sample) @cw.on_frame(twin_uuid) def servoing(frame, ctx): joints = fusion.at("joint_states", t=ctx.timestamp, interpolation="linear") ``` ### Interpolation strategies | Strategy | Use case | Behavior | | ----------- | --------------------------------------------------- | --------------------------------------------------------- | | `"linear"` | Scalar, vector, dict, numpy, `Quaternion` | Element-wise linear interpolation (NLERP for quaternions) | | `"slerp"` | `Quaternion` channels (attitude, end-effector pose) | Spherical linear interpolation | | `"nearest"` | Non-numeric or discrete channels | Returns closest sample by time | | `"none"` | Exact match only | Returns `None` if no exact match | Dict interpolation operates over the **union** of keys from both samples and emits a `UserWarning` when the schemas diverge (schema drift detection). ### `Quaternion` type SLERP only triggers when values are wrapped in `Quaternion`. Plain `list[float]` of length 4 will **not** be SLERPed — this avoids ambiguity with RGBA colors, 4-DOF joint arrays, etc. ```python theme={null} from cyberwave.data import Quaternion fusion.ingest("orientation", ts, Quaternion(x=0, y=0, z=0.707, w=0.707)) pose = fusion.at("orientation", t=ctx.timestamp, interpolation="slerp") # pose is a Quaternion instance ``` Convention: Hamilton `(x, y, z, w)` — the same as ROS, MuJoCo, and the Cyberwave wire format. ## `data.window()` — Time-range query Return all buffered samples within a time range. The returned `WindowResult` is iterable. ```python theme={null} imu_samples = fusion.window("imu", from_t=prev_frame_ts, to_t=ctx.timestamp) recent_ft = fusion.window("force_torque", duration_ms=100) for sample in recent_ft: process(sample.ts, sample.value) ``` Returns an empty `WindowResult` for unknown channels. ## Use cases | Use case | Primitive | Why | | ----------------------- | ------------------------------ | --------------------------------------------------- | | Force-reactive grasping | `data.at(t=ctx.timestamp)` | Force reading must match arm pose at contact | | Conveyor pick-and-place | `data.at(t=ctx.timestamp)` | Object position at detection time projected forward | | VIO pre-integration | `data.window(from_t=, to_t=)` | Full IMU series between camera keyframes | | Force filtering | `data.window(duration_ms=100)` | Moving average over recent F/T samples | | Jerk estimation | `data.window(duration_ms=50)` | Second derivatives require recent position history | ## Buffer configuration Each channel gets a `deque`-backed ring buffer (default: 1000 samples, O(1) eviction). Configure per-channel depth before the first `ingest()`: ```python theme={null} fusion.configure_channel("imu", capacity=5000) ``` Calling `configure_channel` after samples have already been ingested raises `ValueError`. ## Custom clock `FusionLayer` accepts an optional `clock` argument (defaults to `time.time`). Use this to align with a monotonic or sim-time source: ```python theme={null} from cyberwave.data import FusionLayer import time fusion = FusionLayer(clock=time.monotonic) ``` # Record & replay Source: https://docs.cyberwave.com/feature-reference/edge/drivers/data-record-replay Capture live edge data to disk and replay it for deterministic debugging ## Overview The SDK data layer includes `record()` and `replay()` utilities that let you capture live samples to disk and replay them later. Replayed samples flow through the same backend as live data, re-triggering any active hooks and subscribers. ## Quick start ```python theme={null} from cyberwave.data import get_backend from cyberwave.data.recording import record, replay backend = get_backend() # Record live samples with record(backend, ["frames/default", "depth"], "/tmp/session1"): # ... samples flow through the backend while this block runs pass # Replay recorded samples result = replay(backend, "/tmp/session1", speed=1.0) print(f"Replayed {result.samples_published} samples") ``` ## Recording `record()` returns a `RecordingSession` context manager. It subscribes to the specified channels using `policy="fifo"` and writes every incoming sample to per-channel `.bin` files inside the target directory. ```python theme={null} # Record with limits session = record( backend, channels=["frames/default", "joint_states"], path="/data/recordings/session_001", max_samples=1000, # stop after 1000 samples max_duration_s=60.0, # or after 60 seconds ) # ... later manifest = session.stop() ``` The recording directory contains: | File | Contents | | --------------- | ------------------------------------------- | | `manifest.json` | Version, channels, timestamps, sample count | | `.bin` | Binary stream of timestamped sample entries | ## Replay `replay()` reads a recording directory and publishes each sample back through the backend, preserving inter-sample timing. ```python theme={null} from cyberwave.data.recording import replay # Real-time replay replay(backend, "/data/recordings/session_001", speed=1.0) # 2x speed replay(backend, "/data/recordings/session_001", speed=2.0) # As fast as possible (no sleep between samples) replay(backend, "/data/recordings/session_001", speed=0) # Replay specific channels only replay(backend, "/data/recordings/session_001", channels=["frames/default"]) # Loop continuously replay(backend, "/data/recordings/session_001", loop=True) ``` ## Replay timeline markers Replays with video now expose historical alert markers and selected telemetry markers on the timeline. Operators can filter those markers and the replay tracks by twin while reviewing live-originated and simulation-originated sessions. ## Portability Recordings are plain files with no backend-specific data. You can record on one backend (e.g. Zenoh) and replay on another (e.g. filesystem), or transfer recordings between machines. # Synchronized multi-channel hooks Source: https://docs.cyberwave.com/feature-reference/edge/drivers/data-synchronized-hooks Approximate time synchronizer that fires a callback when samples from all listed channels arrive within a configurable tolerance. `@cw.on_synchronized` is an approximate time synchronizer for edge workers that need to fuse data from multiple sensors with temporal guarantees. ## Usage ```python theme={null} @cw.on_synchronized(twin_uuid, ["frames/front", "depth/default", "joint_states"], tolerance_ms=50) def detect_collision(samples, ctx): frame = samples["frames/front"].payload depth = samples["depth/default"].payload joints = samples["joint_states"].payload # All three are within 50ms of each other ``` ## Callback signature ```python theme={null} def handler(samples: dict[str, Sample], ctx: HookContext) -> None: ... ``` | Parameter | Type | Description | | --------------- | ------------------- | ------------------------------------------------------- | | `samples` | `dict[str, Sample]` | Dict keyed by channel name; values are `Sample` objects | | `ctx.timestamp` | `float` | Max of all sample timestamps | | `ctx.metadata` | `dict` | Contains `synchronized_channels` list | ## How it works 1. For each channel in the list, a separate data-layer subscription is created. 2. A shared `latest_samples` buffer (one entry per channel) is maintained under a lock. 3. On each incoming sample the buffer is updated, then checked: if all channels are present **and** `max(timestamps) - min(timestamps) <= tolerance_ms / 1000`, the callback fires with a copy of the buffer. 4. Exceptions in the callback are logged; the runtime continues. ## Cross-twin mode For multi-camera or cross-device fusion, use `twin_channels` to synchronize channels from different twins: ```python theme={null} @cw.on_synchronized( twin_channels={ "left": (CAMERA_LEFT, "frames/default"), "right": (CAMERA_RIGHT, "frames/default"), }, tolerance_ms=50.0, ) def on_stereo_pair(samples, ctx): left = samples["left"] # Sample from CAMERA_LEFT twin right = samples["right"] # Sample from CAMERA_RIGHT twin # ctx.metadata["twin_uuids"] lists the involved twins ``` The single-twin API (`@cw.on_synchronized(twin_uuid, channels)`) continues to work unchanged. See [Multi-Camera Detection Routing](/feature-reference/edge/drivers/multi-camera-detection-routing) for an end-to-end example. ## Comparison with `latest(max_age_ms=)` | Approach | Guarantee | Use case | | ----------------------------------------------------------- | ------------------------------ | --------------------------------------- | | `cw.data.latest(ch, max_age_ms=50)` | Single-channel staleness check | Pull-based fusion inside `@cw.on_frame` | | `@cw.on_synchronized(twin_uuid, channels, tolerance_ms=50)` | All channels within tolerance | Push-based multi-sensor fusion | ## Temporal sync roadmap | Phase | Primitive | Status | | ----- | ----------------------------------------- | ---------------- | | 0 | `timestamp` in every `Sample` | Done | | 1 | `latest(max_age_ms=)` | Done | | **2** | **`@cw.on_synchronized()`** | **This feature** | | 3 | `cw.data.at(channel, t=, interpolation=)` | Planned | | 4 | `cw.data.window(channel, from_t=, to_t=)` | Planned | # Data wire format Source: https://docs.cyberwave.com/feature-reference/edge/drivers/data-wire-format SDK header encoding, key expressions, and on-wire contract for edge data channels ## Wire frame layout Every sample on the Cyberwave data bus (Zenoh or filesystem) uses one framing: | Field | Type | Size | | ------------ | ------- | -------- | | `header_len` | u32, LE | 4 bytes | | `ts` | f64, LE | 8 bytes | | `seq` | i64, LE | 8 bytes | | header JSON | UTF-8 | variable | | payload | bytes | variable | * `header_len` — 4-byte LE uint32 covering `ts` + `seq` + JSON. * `ts` — 8-byte LE float64, acquisition timestamp (Unix epoch seconds). Binary-packed for O(1) read. * `seq` — 8-byte LE int64, per-channel sequence number for drop detection. * Header JSON — compact UTF-8 JSON with at least `content_type` and channel-specific metadata. * Payload — raw bytes (numpy buffer) or UTF-8 JSON. The `HeaderTemplate` class pre-encodes the JSON once and splices only `ts`/`seq` per sample (\<500 ns overhead). ## Key expression pattern ``` cw/{twin_uuid}/data/{channel}/{sensor_name} ``` | Segment | Description | | ------------- | ----------------------------------------------------- | | `cw` | Prefix (configurable via `BackendConfig.key_prefix`). | | `twin_uuid` | UUID-4 of the digital twin. | | `data` | Fixed literal. | | `channel` | Channel name (`frames`, `joint_states`, etc.). | | `sensor_name` | Optional qualifier (`default`, `wrist`, `left_arm`). | ## Usage ### Encoding / decoding with HeaderTemplate (hot path) ```python theme={null} from cyberwave.data import HeaderTemplate, decode tmpl = HeaderTemplate("numpy/ndarray", shape=(480, 640, 3), dtype="uint8") wire = tmpl.pack(frame_bytes, ts=time.time()) # <500ns header overhead header, payload = decode(wire) ``` ### One-shot encode / decode ```python theme={null} from cyberwave.data import HeaderMeta, encode, decode hdr = HeaderMeta(content_type="application/json", ts=time.time()) wire = encode(hdr, b'{"x": 1.0}') header, payload = decode(wire) ``` ### Building and parsing key expressions ```python theme={null} from cyberwave.data import build_key, parse_key, is_valid_key key = build_key("550e8400-e29b-41d4-a716-446655440000", "frames", "default") # → "cw/550e8400-e29b-41d4-a716-446655440000/data/frames/default" ke = parse_key(key) assert ke.channel == "frames" assert ke.is_stream is True assert is_valid_key(key) ``` ## Well-known channels | Channel | Pattern | Encoding | | ------------------- | ------------ | -------- | | `frames` | Stream | binary | | `depth` | Stream | binary | | `audio` | Stream | binary | | `pointcloud` | Stream | binary | | `imu` | Stream | JSON | | `force_torque` | Stream | JSON | | `joint_states` | Latest value | JSON | | `position` | Latest value | JSON | | `attitude` | Latest value | JSON | | `gps` | Latest value | JSON | | `end_effector_pose` | Latest value | JSON | | `gripper_state` | Latest value | JSON | | `map` | Latest value | binary | | `battery` | Latest value | JSON | | `temperature` | Latest value | JSON | | `telemetry` | Latest value | JSON | # Driver mixins and capabilities Source: https://docs.cyberwave.com/feature-reference/edge/drivers/driver-mixins Compose cyberwave.driver mixins for arm teleop, joint feedback, motion shaping, and sensor streams. ## Overview Edge drivers are built by **composing mixins** on [`BaseDriver`](/feature-reference/edge/drivers/base-driver-class) or [`BaseROS2Driver`](/feature-reference/edge/drivers/ros2-base-driver). Each mixin registers part of the MQTT catalog and supplies **seams** (methods you implement) for hardware-specific behavior. Import the public surface from `cyberwave.driver`: ```python theme={null} from cyberwave.driver import ( ArmCapabilityMixin, JointCommandBufferMixin, JointControllerMixin, TopicSpec, ) from cyberwave.driver.ros2 import BaseROS2Driver, Ros2JointFeedbackMixin, Ros2TopicSpec ``` *** ## Composition order (MRO) **Method resolution order matters.** Put `JointControllerMixin` **before** `ArmCapabilityMixin` so joint targets from teleop and arm commands (`ee_move`, `grip`, …) both flow through `JointControllerMixin._apply_joint_targets`. The Piper driver uses this exact stack: ```python theme={null} class PiperDriver( JointControllerMixin, ArmCapabilityMixin, Ros2JointFeedbackMixin, JointCommandBufferMixin, BaseROS2Driver, ): use_joint_controller = True use_joint_feedback = True use_base_commands = True ``` See [Reference pattern: Agilex Piper](#reference-pattern-ros-manipulator-arm-agilex-piper) for how `__init__`, `define_interface`, and `tick()` tie the mixins together at runtime. *** ## Mixin reference | Mixin | Enable flag | You implement | SDK registers / provides | | ------------------------------------------------------ | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | **`JointControllerMixin`** | `use_joint_controller=True` | `joint_controller_config()`, `joint_controller_after_process()`; optional `joint_controller_motion()` | `joint/update` **listener** (`tele`, `edit`, `sim_tele`); shapes targets via `JointController.plan` | | **`JointCommandBufferMixin`** | — (always compose for ROS arms) | `_init_joint_command_buffer()` in `__init__`, `_publish_joint_command()`, `_return_to_home()`, `tick()` → `pump_joint_commands()` | Thread-safe `CommandInbox`; teleop counters; optional `HOME_ON_TEARDOWN` | | **`ArmCapabilityMixin`** | `use_base_commands=True` | `arm_config()` → `ArmKinematicsConfig` | `twin/command` listeners: `ee_move`, `ee_rotate_*`, `grip`, `release`, `home`, … | | **`EECartesianPoseMixin`** | — | EE pose seams | Cartesian command extensions | | **`DualArmMixin`** | — | `DualArmConfig` + per-arm routing | `left_*` / `right_*` commands on one twin | | **`Ros2JointFeedbackMixin`** | `use_joint_feedback=True` | `joint_feedback_topic()`, `joint_name_map()`; optional `on_first_joint_feedback()` | ROS `JointState` subscription; `convert_joints_to_payload()` for `from_ros` | | **`VideoStreamMixin`** | — | Frame publish hooks | WebRTC / video catalog | | **`AudioStreamMixin`** | — | Audio stream hooks | Microphone catalog | | **`ZenohPublisherMixin`** / **`ZenohSubscriberMixin`** | — | Channel callbacks | Zenoh catalog entries | ### Control types (no mixin — used by mixins) | Type | Role | | ----------------------- | --------------------------------------------------------- | | `JointController` | Plans waypoint streams from target dicts | | `JointControllerConfig` | Joint list, `passthrough_joints`, limits | | `trapezoidal_motion` | Default motion generator | | `JointNameMap` | ROS ↔ platform joint renaming (e.g. `gripper` → `joint7`) | | `MotionGenerator` | Plug-in profile (`motion=None` = passthrough) | See [Joint motion shaping](/feature-reference/edge/drivers/joint-motion-shaping) for shaped vs passthrough motion. *** ## Bidirectional `joint/update` The `cyberwave/joint/{uuid}/update` topic carries **both** teleop commands and edge feedback. Split responsibility: | Direction | `source_type` | Who registers it | | ------------------------- | -------------------------- | ------------------------------------------------------------------------------- | | **Feedback** (ROS → MQTT) | `edge` | **Your** `define_interface` → `add_publisher(..., from_ros=Ros2TopicSpec(...))` | | **Teleop** (MQTT → ROS) | `tele`, `edit`, `sim_tele` | **`JointControllerMixin`** — do **not** add a second `joint/update` listener | Teleop listeners **reject `edge*`** messages so the driver never re-ingests its own feedback. *** ## Reference pattern: ROS manipulator arm (Agilex Piper) The **[Agilex Piper driver](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-edge-nodes/piper/piper_driver.py)** (`PiperDriver`) is the canonical integration: five base classes, a handful of seams, and **one** `define_interface` publisher — no hand-written MQTT joint bridge. ### How the pieces connect Mixins do not run in isolation. They wire together through **shared state** (`_joint_states`, `_tele_inbox`), **`super()` calls**, and the ROS **`tick()`** timer: ```mermaid theme={null} flowchart LR subgraph mqtt_in [MQTT in] JT[joint/update tele] TC[twin/command] end subgraph mixins [SDK mixins] JCM[JointControllerMixin] ACM[ArmCapabilityMixin] JBuf[JointCommandBufferMixin] RJF[Ros2JointFeedbackMixin] end subgraph ros [ROS graph] CMD[joint_ctrl_cmd] FB[joint_states_single] end subgraph mqtt_out [MQTT out] JE[joint/update edge] end JT --> JCM TC --> ACM ACM --> JCM JCM --> JBuf JBuf -->|tick pump| CMD FB --> RJF FB -->|from_ros| JE RJF -->|_joint_states IK| ACM ``` | Phase | What runs | Piper-specific | | ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------- | | **Class + flags** | MRO resolves mixin methods | `use_joint_controller`, `use_joint_feedback`, `use_base_commands`; `HOME_ON_TEARDOWN`, `EDGE_HEALTH_INTERVAL_S = 1` | | **`__init__`** | Buffer + feedback init | `_init_joint_feedback()` then `_init_joint_command_buffer()` after `super().__init__` | | **`configure()`** | ROS params, name map | `JointNameMap.from_arm_config(arm_config(), ros_to_platform={"gripper": "joint7"})` | | **`define_interface`** | Catalog compile | `super().define_interface(iface)` registers mixin **listeners**; Piper adds **only** the `from_ros` **publisher** | | **`register_callbacks`** | Extra ROS subs | Piper adds `arm_status` (vendor diagnostics — not part of mixin contract) | | **`tick()`** | Executor timer | `pump_joint_commands()` drains inbox → `_publish_joint_command` | | **Activate / teleop** | Operation mode | `on_enter_teleop_*` → enable service + CAN prime; **NO\_OP** still streams edge feedback | ### Class declaration and flags ```python theme={null} class PiperDriver( JointControllerMixin, # joint/update listener + planning seam ArmCapabilityMixin, # twin/command (ee_move, grip, home, …) Ros2JointFeedbackMixin, # ROS JointState → local _joint_states JointCommandBufferMixin, # MQTT thread → ROS executor hand-off BaseROS2Driver, ): use_joint_controller = True use_joint_feedback = True use_base_commands = True HOME_ON_TEARDOWN = True ``` `JointControllerMixin` **must** precede `ArmCapabilityMixin` so IK-produced joint targets and MQTT teleop both enter `JointControllerMixin._apply_joint_targets`. ### `__init__` — wire mixin state ```python theme={null} def __init__(self, node_name: str, manifest_path: str | None = None, **kwargs): super().__init__(node_name, manifest_path, **kwargs) self._init_joint_feedback() # Ros2JointFeedbackMixin self._init_joint_command_buffer() # JointCommandBufferMixin ``` Without these two calls the inbox, teleop counters, and `_joint_states` cache are never allocated. ### `define_interface` — feedback publisher only `super().define_interface(iface)` lets mixins register `joint/update` **listener** and `twin/command` **listeners**. Piper adds the outbound path: ```python theme={null} def define_interface(self, iface) -> None: super().define_interface(iface) iface.add_publisher( TopicSpec( namespace="joint", leaf="update", payload_schema_ref="JointStatesPayload", rate_hz=30.0, # JOINT_FEEDBACK_MQTT_RATE_HZ description="Edge joint feedback from joint_states_single", ), CallbackGroup(), operation_modes=frozenset(DriverOperationMode), protocol=ProtocolArgs(source_types=[SOURCE_TYPE_EDGE]), from_ros=Ros2TopicSpec(topic="joint_states_single"), ) ``` At runtime `wire_ros_publishers()` subscribes on ROS, calls `convert_joints_to_payload` (uses `joint_name_map()`), throttles to `rate_hz`, and publishes with `source_type=edge`. **Do not** add a second `joint/update` listener — `JointControllerMixin` already owns teleop. ### Seam map — what Piper implements per mixin | Mixin | Seam | Piper implementation | | ----------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------- | | **`JointControllerMixin`** | `joint_controller_config()` | `joint1`–`joint7`; `passthrough_joints=("joint7",)` for gripper | | | `joint_controller_motion()` | `return None` — Piper shapes velocity/effort in the ROS `JointState` cmd, not SDK trapezoidal | | | `joint_controller_after_process()` | `lambda cmd: self.submit_joint_targets(cmd.positions)` → inbox | | **`JointCommandBufferMixin`** | `tick()` | `self.pump_joint_commands()` | | | `_publish_joint_command(positions)` | `ros_publish(cmd_topic, build_joint_command_msg(...))` with vendor vel/effort | | **`ArmCapabilityMixin`** | `arm_config()` | `build_piper_arm_config(urdf_path=…)` for IK | | **`Ros2JointFeedbackMixin`** | `joint_feedback_topic()` | `"joint_states_single"` (ROS param override in `configure`) | | | `joint_name_map()` | `gripper` ↔ `joint7` via `JointNameMap` | Command path end-to-end: ```text theme={null} twin.joints.set() / MQTT joint/update (tele) → JointControllerMixin._on_joint_target → JointController.plan (passthrough when motion=None) → joint_controller_after_process → submit_joint_targets → tick() → pump_joint_commands → _publish_joint_command → ros_publish("joint_ctrl_cmd", JointState) twin.commands.ee_move() / grip / home → ArmCapabilityMixin IK → same JointController.plan path as above ``` Feedback path (two consumers, one ROS topic): ```text theme={null} ROS joint_states_single → Ros2JointFeedbackMixin._on_joint_feedback → _joint_states (IK, latch_gripper, prime) → from_ros forwarder → MQTT joint/update @ 30 Hz, source_type=edge ``` ### Passthrough motion vs shaped Piper returns `None` from `joint_controller_motion()` so targets pass straight through; velocity and effort limits come from ROS parameters (`joint_velocities`, `joint_efforts`, `gripper_effort`) inside `_build_joint_command_msg()`. Arms that need SDK-side smoothing return `trapezoidal_motion` instead — see [Joint motion shaping](/feature-reference/edge/drivers/joint-motion-shaping). ### Operation modes and edge health * **`NO_OP`**: Piper resets the teleop inbox but keeps ROS lifecycle **Active** so `from_ros` feedback continues (`on_enter_no_op`). * **Teleop**: `on_enter_teleop_local` / `remote` call vendor enable + CAN prime; commands flow only when hardware accepts them. * **Liveness**: `_touch_edge_health()` on joint and arm-status callbacks; `edge_health` publishes at 1 Hz — no extra payload in `edge_health_extras`. ### What stays driver-specific (not mixin) Piper still owns vendor glue that mixins do not cover: `managed_launch` (piper\_ros), CAN setup, `/enable_srv`, `arm_status` subscription, and homing repeats on teardown (`HOME_ON_TEARDOWN`). Mixins handle the **Cyberwave contract**; the driver handles **hardware bring-up**. ### Client APIs vs driver plumbing | API | Use | | -------------------------------------- | ----------------------------------------------------------- | | `define_interface` + `from_ros` | **Edge drivers** — ROS measured state → MQTT | | `client.mqtt.update_joints_state(...)` | Scripts, sims, non-registry publishers | | `twin.joints.set(...)` | **Application teleop** — commands only, not driver feedback | End users call `twin.joints.set()` / `twin.joints.get()`; they do not implement `from_ros`. *** ## Related Dual lifecycle, `from_ros`, `wire_ros_publishers`, manifest export. Trapezoidal vs passthrough `joint_controller_motion()`. Platform contract, MQTT catalog, env vars. Production reference — mixin integration, passthrough motion, managed launch. # How edge workers work Source: https://docs.cyberwave.com/feature-reference/edge/drivers/edge-workers Hook-based worker modules for on-device ML inference and event-driven processing at the edge. ## Overview Edge workers are Python modules that run inside worker containers on edge devices. Each worker declares **hooks** (callbacks for sensor data) and **model loading** using the `cw` client—no imports needed. **Architecture:** one edge device → one worker container → one runtime → many worker modules. ## Quick Example ```python theme={null} # /app/workers/detect_people.py — loaded by the runtime automatically model = cw.models.load("yolov8n") twin_uuid = cw.config.twin_uuid @cw.on_frame(twin_uuid, sensor="front") def detect_people(frame, ctx): results = model.predict(frame, classes=["person"], confidence=0.5) for det in results: if det.area_ratio > 0.3: cw.publish_event(twin_uuid, "person_too_close", { "detections": len(results), "frame_ts": ctx.timestamp, }) ``` ## Hook Decorators Register callbacks for sensor streams. Hooks are passive at import time—the runtime activates them. | Decorator | Channel | Sensor kwarg | | -------------------------------------- | --------------------------------------------- | ------------ | | `@cw.on_frame(uuid, sensor=None)` | `frames/{sensor}` (wildcard when omitted) | `sensor` | | `@cw.on_depth(uuid, sensor=None)` | `depth/{sensor}` (wildcard when omitted) | `sensor` | | `@cw.on_audio(uuid, sensor=None)` | `audio/{sensor}` (wildcard when omitted) | `sensor` | | `@cw.on_pointcloud(uuid, sensor=None)` | `pointcloud/{sensor}` (wildcard when omitted) | `sensor` | | `@cw.on_lidar(uuid, sensor=None)` | `lidar/{sensor}` (wildcard when omitted) | `sensor` | | `@cw.on_imu(uuid)` | `imu` | — | | `@cw.on_joint_states(uuid)` | `joint_states` | — | | `@cw.on_gps(uuid)` | `gps` | — | | `@cw.on_battery(uuid)` | `battery` | — | | `@cw.on_data(uuid, channel)` | custom | — | All callbacks receive `(sample_payload, ctx)` where `ctx` is a `HookContext` with `timestamp`, `channel`, `sensor_name`, `twin_uuid`, and `metadata`. Passing `sensor=None` (or omitting it) subscribes to every sensor of that type on the twin — the SDK constructs a `frames/**` (or `depth/**`, etc.) wildcard key expression. `ctx.sensor_name` is populated from the observed publish key so a single handler can disambiguate multi-sensor twins. Pin `sensor=""` (e.g. `"color_camera"`) when you need to target one specific sensor — the name must match what the twin asset declares. ## Model Loading ```python theme={null} model = cw.models.load("yolov8n") # auto-detect runtime model = cw.models.load("my-model", runtime="ultralytics", device="cuda:0") result = model.predict(frame, confidence=0.5, classes=["person"]) ``` `cw.models.load()` caches models — safe to call at module level. ## Publishing Events ```python theme={null} cw.publish_event(twin_uuid, "event_type", {"key": "value"}) ``` Publishes to `cyberwave/twin/{uuid}/event` via MQTT. Payload matches the backend `mqtt_consumer.handle_business_event()` schema. ## Configuration | Env var | Purpose | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CYBERWAVE_TWIN_UUID` | Twin UUID, available as `cw.config.twin_uuid` | | `CYBERWAVE_WORKERS_DIR` | Workers directory (default: `/app/workers`) | | `CYBERWAVE_MODEL_DIR` | Model weights directory (default: `/app/models`) | | `CYBERWAVE_MODEL_DEVICE` | Default inference device. Unset = auto-detect, which probes both a conv2d (cuDNN) and a matmul (cuBLAS) on the GPU and falls back to `cpu` if either fails — the warning names which one. Typical causes: Pascal/sm\_61 on cuDNN 9, an arch missing from the torch build, or a driver/runtime mismatch that breaks `cublasCreate`. Set to `cuda:0` to force GPU, or `cpu` to skip the probe. | ## Runtime Entrypoint Worker modules never call `cw.run_edge_workers()` themselves. The container entrypoint does: ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key=...) cw.run_edge_workers() # loads workers, wires hooks, blocks ``` ## Lifecycle Edge Core starts the worker container only when at least one workflow is active for the connected twins (i.e. the latest sync produced one or more `wf_*.py` files in `{config_dir}/workers/`). When no active workflow exists, the `cyberwaveos/edge-ml-worker` image is not pulled at all. Workflow activations and deactivations are picked up automatically: * **At startup:** after the workflow sync step, the worker container is started if files exist; otherwise startup logs `No active workflows for connected twins; worker container not started` and proceeds. * **At runtime:** every \~5 minutes the workers directory is re-synced; the worker container is started when files appear and stopped when files disappear. Both transitions are idempotent. * **Immediately on activate:** when a `run_on_edge` workflow is activated, the backend publishes a `sync_workflows` MQTT command on each referenced twin's command topic; Edge Core runs an immediate sync and lifecycle reconcile so the new `wf_*.py` lands within seconds. * **Immediately on remove (deactivate / soft-delete / `run_on_edge` flip off):** the backend publishes a surgical `remove_workflow_worker` MQTT command naming the specific worker filename(s); Edge Core unlinks the file from `{config_dir}/workers/` and immediately reconciles the container lifecycle. The same nudge also fires when a workflow is removed as part of a workspace or environment teardown. Removal propagates within seconds instead of waiting up to \~5 minutes for the periodic sync plus the bulk-sync two-strikes cleanup. The periodic reconcile remains the correctness backstop. `cyberwave edge sync-workflows --twin-uuid ` (or `cyberwave workflow sync `) from the CLI triggers an immediate sync via MQTT, which reuses the same lifecycle path on the next reconcile. # Frame substitution Source: https://docs.cyberwave.com/feature-reference/edge/drivers/frame-filters Substitute a worker-processed frame into a camera driver's WebRTC stream — for anonymisation, redaction, or overlay pipelines. ## Why By default the camera driver streams **raw** frames over WebRTC. For privacy-sensitive deployments (security cameras, retail floors, hospitals) you usually want a worker to **transform every frame** — for example, replacing each person's silhouette with a stick figure — **before** the bytes leave the edge. The frame filter contract lets a worker do that without owning the WebRTC stack. **Substitution vs. overlay.** The flow on this page covers *frame substitution* — the driver swaps in worker-produced pixels — and is gated on the per-twin `frame_filter_enabled` privacy flag. It applies to the [`anonymize`](/feature-reference/workflows/anonymize-image) workflow node. The `annotate` node uses a separate, additive overlay channel that the driver subscribes to unconditionally, so it does not need this flag — see [Workflows](/feature-reference/workflows) and *Annotation overlays* below. ## How it works ```mermaid theme={null} flowchart LR Cam[Camera] --> Driver Driver -->|raw frame| Zenoh[("frames/default")] Zenoh --> Worker Worker -->|filtered frame| Filtered[("frames/filtered")] Filtered --> Driver Driver -->|substituted frame| WebRTC[WebRTC ⟶ Frontend] ``` 1. The driver publishes every captured frame to a local Zenoh channel (`frames/default`). 2. A worker subscribes, runs inference / anonymisation, and publishes the result to `cyberwave.data.FILTERED_FRAME_CHANNEL` (literal value `"frames/filtered"`). 3. Before encoding for WebRTC, the driver consults the latest filtered frame. If one is available, fresh (≤200 ms old) and matches the raw frame's `shape` and `dtype`, it is sent instead of the raw frame. Otherwise a black frame is emitted. Per-twin isolation is automatic: the data bus injects the twin UUID into the Zenoh key (`cw//data/frames/filtered`), so multiple cameras on the same edge box don't collide. The driver owns the stream lifecycle. The worker owns the policy. Toggling the filter on or off at the driver level is a single per-twin metadata flag — no code changes to the worker. ## Privacy boundary `frames/*` channels are **local-only**: the Zenoh-MQTT bridge does NOT forward them to the cloud by default. Only events, detections and overlays cross the WAN. See [Edge Workers](./edge-workers) for the hook contract. ## Configuration (driver side) | Variable | Default | Purpose | | ---------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CYBERWAVE_METADATA_FRAME_FILTER_ENABLED` | `false` | Set `true` to subscribe the driver to `FILTERED_FRAME_CHANNEL` and substitute worker frames into the WebRTC stream. | | `CYBERWAVE_METADATA_FRAME_FILTER_FRESHNESS_MS` | `200` | Maximum age (ms) of a worker-published frame before the driver treats it as stale and emits a blank fallback. Raise to `400`–`500` for CPU-only workers. | Toggling `frame_filter_enabled` from the **Sensor settings** dialog in the frontend writes it onto the twin's `metadata`. Edge Core's reconcile loop pulls that change into the local twin JSON file every \~15 seconds, and the driver picks it up on its next restart. No `edge-core` restart is required. There is intentionally no "raw fallback" knob: when the worker is slow, missing, crashed, or publishing the wrong frame shape/dtype, the driver emits a black frame. To debug what the camera sees, disable the filter entirely. **Worker-side privacy gate.** Workers generated from an [`anonymize`](/feature-reference/workflows/anonymize-image) workflow node go one step further: when the model returns zero detections matching the configured `target_classes`, the worker publishes `np.zeros_like(frame)` to `FILTERED_FRAME_CHANNEL` rather than the (untouched) raw frame `blank_persons` would otherwise pass through. This closes the case where a detector miss on a single frame would have leaked raw pixels through a fresh, well-formed publish — the driver-side fail-closed only catches stale and shape-mismatched frames. ### Operational logging Stale and shape-mismatch fall-throughs are accumulated into a 30-second rolling window and surfaced as a single summary log per window: ``` [FRAME_FILTER] 1.2% of 870 frames in last 30 s emitted blank fallback on 'frames/filtered' (reasons: stale=11). Worker may be slow or freshness window too tight; consider raising CYBERWAVE_METADATA_FRAME_FILTER_FRESHNESS_MS if pixelation occasionally drops out. ``` The advice line switches to **"Worker likely down or not publishing on this channel"** when the blank rate exceeds 90% in a window, so a 1% jitter and a fully-missing worker are easy to tell apart in logs. ## Worker side A worker uses any standard hook (`@cw.on_frame`, `@cw.on_depth`, ...) to receive frames, runs its model, and publishes the result back to the shared channel constant. The published frame **must match the raw camera frame's `shape` and `dtype`** — otherwise the driver drops it fail-closed. ```python theme={null} from cyberwave.data import FILTERED_FRAME_CHANNEL from cyberwave.vision import anonymize_frame model = cw.models.load("yolov8n-pose-onnx") twin_uuid = cw.config.twin_uuid @cw.on_frame(twin_uuid, sensor="front") def anonymise(frame, ctx): detections = model.predict(frame, classes=["person"], confidence=0.4) out = anonymize_frame(frame, detections.detections) # uint8 BGR, same shape cw.data.publish(FILTERED_FRAME_CHANNEL, out, twin_uuid=twin_uuid) ``` See the [security pipeline example](./edge-workers) for an end-to-end multi-camera setup. ## Annotation overlays The `annotate` workflow node (see [Workflows](/feature-reference/workflows)) takes a different path from the substitution flow above. Instead of rewriting pixels, it publishes a small JSON overlay spec — boxes, labels, and styling — to `cyberwave.data.FRAME_OVERLAY_CHANNEL` (literal value `"frames/overlay"`). The camera driver subscribes to this channel unconditionally and composites the boxes onto the frame just before WebRTC encoding. Two consequences worth knowing: * The per-twin `frame_filter_enabled` flag does **not** apply. Annotation overlays appear in the WebRTC stream regardless. (Pixel substitution still requires the flag — annotation just doesn't ride that path.) * A failure in the annotate worker results in **missing boxes**, not a black frame. Substitution is fail-closed for privacy reasons; overlay is fail-open because losing boxes is not a privacy regression. ### Segmentation overlays When the upstream `call_model` node runs an instance-segmentation model (e.g. YOLO-seg), each detection in the overlay payload carries an optional `polygon` field (list of `[x, y]` vertices in original-frame coordinates). The driver composites a translucent fill (`style.mask_alpha`, default `0.35`) and an outline (`style.mask_outline`, default `true`) onto the WebRTC frame at encode time — additive to the standard box + caption. The v1 polygon encoding uses each instance's largest external contour and silently drops holes; downstream pipelines that need the raw mask should set the annotate node's `mask_format` to `"polygon+png"` and consume `mask_b64` cloud-side. # Joint motion shaping Source: https://docs.cyberwave.com/feature-reference/edge/drivers/joint-motion-shaping Shape joint commands with velocity-constrained smooth motion in custom drivers ## When to use it Enable **`JointControllerMixin`** (`use_joint_controller=True`) when MQTT `joint/update` teleop targets should be **smoothed** before reaching hardware — instead of applying every target instantly. Arm commands (`ee_move`, `grip`, …) from **`ArmCapabilityMixin`** use the same controller path when both mixins are composed. Full mixin composition: [Driver mixins and capabilities](/feature-reference/edge/drivers/driver-mixins). *** ## Default: trapezoidal motion With no override, `joint_controller_motion()` returns **`trapezoidal_motion`**. The controller: * Reads current positions from `_current_joint_positions()` (often via `Ros2JointFeedbackMixin`) * Builds a time-parameterized waypoint stream from velocity limits * Calls `joint_controller_after_process()` for each waypoint (typically `submit_joint_targets` → `tick()` → hardware) Move duration is driven by the largest joint delta ÷ its velocity constraint (from arm kinematics when available). *** ## Passthrough mode Return **`None`** from `joint_controller_motion()` to forward a **single waypoint** per target with no SDK shaping: ```python theme={null} def joint_controller_motion(self): return None # passthrough ``` Use passthrough when the vendor stack already applies velocity/effort in the native command message (common on ROS `JointState` command topics). The Agilex Piper driver follows this pattern: MQTT targets queue immediately; Piper-specific templates live in the ROS publish path. *** ## Custom generators Implement a **`MotionGenerator`** callable and return it from `joint_controller_motion()` for alternate profiles (minimum-jerk, s-curve, etc.). See `cyberwave.driver.control.motion` in the Python SDK. *** ## Required seams | Method | Purpose | | ---------------------------------- | ----------------------------------------------------------- | | `joint_controller_config()` | `JointControllerConfig(joints=..., passthrough_joints=...)` | | `joint_controller_after_process()` | Write seam after each planned waypoint | | `joint_controller_motion()` | Optional — default trapezoidal; `None` = passthrough | **Do not** register your own `joint/update` listener when `use_joint_controller=True` — the mixin owns teleop ingress. *** ## Related * [Driver mixins](/feature-reference/edge/drivers/driver-mixins) — MRO, `JointCommandBufferMixin`, bidirectional `joint/update` * [BaseROS2Driver](/feature-reference/edge/drivers/ros2-base-driver) — `from_ros` feedback vs teleop listener # Multi-camera detection routing Source: https://docs.cyberwave.com/feature-reference/edge/drivers/multi-camera-detection-routing Route detection results to the correct twin when a single worker handles frames from multiple cameras. When a single edge worker runs detection models on frames from multiple cameras (each represented by a different digital twin), detection results must be published back to the **correct** twin's Zenoh channel. ## The problem By default, `DataBus` publishes to the twin it was constructed with. In a multi-camera worker, all detections would land on a single twin's channel regardless of which camera produced the frame. ## Solution: `twin_uuid` routing Pass `twin_uuid=ctx.twin_uuid` to `model.predict()` to route detections to the originating twin. ```python theme={null} CAMERA_LEFT = os.environ["CAMERA_LEFT_TWIN"] CAMERA_RIGHT = os.environ["CAMERA_RIGHT_TWIN"] model = cw.models.load("yolov8n") @cw.on_frame(CAMERA_LEFT) def on_left_frame(frame, ctx): model.predict(frame, confidence=0.5, twin_uuid=ctx.twin_uuid) @cw.on_frame(CAMERA_RIGHT) def on_right_frame(frame, ctx): model.predict(frame, confidence=0.5, twin_uuid=ctx.twin_uuid) ``` Each hook's `ctx.twin_uuid` is set from the decorator registration, so `model.predict()` publishes detections to `cw/{twin_uuid}/data/detections/{runtime}` for the correct twin. `ctx.sensor_name` is populated from the observed Zenoh key (e.g. `color_camera`), so a single handler can disambiguate multi-sensor twins at runtime. Omitting `sensor=` subscribes to the twin's `frames/**` wildcard, matching any camera the driver actually publishes. Pin `sensor=""` only when you need to target one specific sensor on a multi-camera twin (the name must match the twin asset's sensor id — typically `color_camera`, `depth_camera`, etc.). ## Cross-twin synchronized hooks For stereo vision or cross-camera fusion, use `@cw.on_synchronized` with `twin_channels` to synchronize frames from different twins: ```python theme={null} @cw.on_synchronized( twin_channels={ "left": (CAMERA_LEFT, "frames/default"), "right": (CAMERA_RIGHT, "frames/default"), }, tolerance_ms=50.0, ) def on_stereo_pair(samples, ctx): left_frame = samples["left"] right_frame = samples["right"] # ctx.metadata["twin_uuids"] contains the sorted list of involved twins ``` The single-twin `@cw.on_synchronized(twin_uuid, channels)` API continues to work unchanged. ## Key API additions | API | Change | | -------------------------------------- | ----------------------------------------- | | `model.predict(..., twin_uuid=)` | Route detections to a specific twin | | `DataBus.publish(..., twin_uuid=)` | Override the default twin for a publish | | `DataBus.publish_raw(..., twin_uuid=)` | Override the default twin for raw publish | | `@cw.on_synchronized(twin_channels=)` | Cross-twin synchronized hook mode | # Multi-camera driver orchestration Source: https://docs.cyberwave.com/feature-reference/edge/drivers/multi-camera-driver-orchestration How Edge Core manages multiple camera drivers alongside a single worker container. When an edge device has multiple cameras (each represented by a separate digital twin), Edge Core starts one driver container per camera and a single shared worker container that receives frames from all of them. ## Architecture ``` ┌──────────────────┐ ┌──────────────────┐ │ cyberwave-driver │ │ cyberwave-driver │ │ (Camera A) │ │ (Camera B) │ │ TWIN_UUID=aaa... │ │ TWIN_UUID=bbb... │ └────────┬─────────┘ └────────┬─────────┘ │ Zenoh frames/default │ ▼ ▼ ┌─────────────────────────────────────────┐ │ cyberwave-worker-{env[:8]} │ │ TWIN_UUIDS=aaa...,bbb... │ │ Subscribes to both camera channels │ └─────────────────────────────────────────┘ ``` ## Driver startup sequencing Edge Core starts drivers **before** the worker and verifies each driver container reaches a `running` state: 1. All linked twins are resolved from the environment. 2. Driver images are pulled in parallel. 3. Containers are started sequentially, each verified with a readiness probe. 4. Once all drivers reach a stable state, the worker container starts. 5. If some drivers fail, the worker still starts (with a warning) so healthy cameras can be utilized. ## Worker environment wiring The worker container receives: | Variable | Value | Purpose | | ---------------------- | --------------------------------------------- | -------------------------------------- | | `CYBERWAVE_TWIN_UUIDS` | Comma-separated list of all linked twin UUIDs | Worker subscribes to all twin channels | | `CYBERWAVE_TWIN_UUID` | First twin UUID (backward compatibility) | Legacy single-twin workers | ## Model pre-download Before the worker starts, Edge Core scans `workers/*.py` for `cw.models.load("...")` calls and pre-downloads all referenced models to the local cache (`~/.cyberwave/models/`). ## CLI visibility `cyberwave edge status` shows: * Each driver container with its twin UUID mapping * The worker container with its full twin list * Running/stopped status for all containers ## Health monitoring Edge Core continuously monitors driver containers during the runtime loop: * **Restart loop detection:** Drivers that restart too frequently are stopped automatically. * **Driver-down alerts:** If a driver stops while the worker is running, an alert is sent to the associated twin. * **Worker health:** The worker container has its own health monitor with circuit-breaker protection against crash loops. ## Related * [Multi-Camera Detection Routing](/feature-reference/edge/drivers/multi-camera-detection-routing) — SDK-level detection routing * [Synchronized Hooks](/feature-reference/edge/drivers/data-synchronized-hooks) — Cross-twin frame synchronization # Native microphone driver Source: https://docs.cyberwave.com/feature-reference/edge/drivers/native-microphone-driver Set up the native Cyberwave microphone driver for WebRTC audio, MQTT start/stop control, and Zenoh audio worker hooks.

Cyberwave is in Private Beta.

Request early access to get access to the Cyberwave dashboard.

## What It Provides The native microphone driver runs on the edge device that has the microphone attached. It captures audio through `sounddevice` / PortAudio, sends a WebRTC audio stream to the twin, and publishes raw chunks to the local Zenoh data bus on `audio/default` by default. It also subscribes to: ```text theme={null} cyberwave/twin/{twin_uuid}/command ``` The driver handles **two independent contracts** on this topic — symmetric with the camera driver's `start_video` / `stop_video` flow: ### 1. Live audio stream (`start_audio` / `stop_audio`) Pure WebRTC lifecycle. **No file is written.** ```json theme={null} { "command": "start_audio", "source_type": "tele", "timestamp": 1716643200.123 } { "command": "stop_audio", "source_type": "tele", "timestamp": 1716643200.123 } ``` The driver replies on `cyberwave/twin/{twin_uuid}/start_audio/status` (or `stop_audio/status`): ```json theme={null} { "type": "audio_started", "status": "ok", "source_type": "edge", "timestamp": 1716643200.123 } { "type": "audio_stopped", "status": "ok", "source_type": "edge", "timestamp": 1716643200.123 } ``` These commands only open or close the WebRTC audio producer — they never trigger recording. ### 2. Recording (`start_recording` / `stop_recording`) The frontend and the **Recorder** workflow node publish directly to: ```text theme={null} cyberwave/twin/{twin_uuid}/webrtc-command ``` ```json theme={null} { "command": "start_recording", "source_type": "tele", "sensor": "audio", "frontend_type": "audio", "session_id": "sdk_9314159f" } { "command": "stop_recording", "source_type": "tele", "sensor": "audio", "frontend_type": "audio", "session_id": "sdk_9314159f" } ``` `source_type` is `"tele"` when the frontend REC button publishes the message and `"edge"` when the microphone driver relays it (fallback path). `session_id` is a free-form correlation hint; the media-service derives the actual recording session from the live SFU producer state and only echoes the field back in its logs. The `sensor` value must match a sensor `id` from `twin.capabilities.sensors` (computed from `twin.universal_schema.sensors[]`); the audio widget resolves it via `getAudioSensorConfig(twin).sensorId`. The REC button is **recording-only**: it never republishes `start_audio` / `stop_audio`. The audio widget auto-publishes `start_audio` on mount and `stop_audio` on unmount, so by the time the user can click REC the WebRTC producer is already running. Re-sending `start_audio` from the REC click would just log `start_audio command received - stream already active` on the driver and add a 3 s ACK wait before the actual recording publish. The media-service SFU starts (or stops) persisting the running audio track and replies on `cyberwave/twin/{twin_uuid}/webrtc-command/status`: ```json theme={null} { "command": "start_recording", "status": "ok", "message": "recording started", "recording_id": "...", "source_type": "backend", "timestamp": 1716643200.123 } ``` As a **fallback path** for callers that only know the twin command topic, the microphone driver also accepts `start_recording` / `stop_recording` on `cyberwave/twin/{twin_uuid}/command` and forwards them verbatim to `webrtc-command`. On the fallback path the driver does **not** publish its own status ACK — callers consume the authoritative status from `webrtc-command/status`. `CYBERWAVE_METADATA_AUTO_RECORDING_AUDIO=true` makes the **initial** WebRTC offer carry `recording: true` so the media-service starts recording in the same negotiation. After startup, recording is controlled entirely by `start_recording` / `stop_recording`. When `CYBERWAVE_METADATA_ENABLE_RECORDING=false`, the driver drops fallback relays silently (the frontend publishes to `webrtc-command` itself and is not affected). ## Setup 1. Create or select a microphone twin in your Cyberwave environment. 2. Pair the edge device through Cyberwave Edge so the driver receives `CYBERWAVE_API_KEY` and `CYBERWAVE_TWIN_UUID`. 3. Attach a USB or built-in microphone to the edge device. 4. Start the driver with Edge Core (recommended) or Docker. On **macOS**, run `cyberwave edge install` so the CLI starts a host ffmpeg PCM bridge (like the MJPEG camera bridge) and Edge Core injects `CYBERWAVE_METADATA_AUDIO_DEVICE=http://host.docker.internal:8101` into the container. On **Linux Docker** hosts, pass the audio device into the container: ```yaml theme={null} devices: - /dev/snd:/dev/snd group_add: - audio ``` Some systems require `--privileged` for ALSA device access. Use the narrower `/dev/snd` mapping first. ## Standard catalog sensor configuration The standard Cyberwave catalog microphone asset declares one sensor block. Both `id` and `name` are `"audio"`; `type` is `"audio"` (active producer). This is the same routing key the [native speaker driver](/feature-reference/edge/drivers/native-speaker-driver) uses for its `id`/`name` — the modalities are distinguished by `type` / WebRTC `sensor_type`, not by `id`. ```json theme={null} { "id": "audio", "name": "audio", "type": "audio", "parameters": { "enable_audio": "true", "audio_channels": "1", "enable_recording": "true", "audio_sample_rate": "48000", "auto_recording_audio": "false" } } ``` Edge-core maps `parameters` → `CYBERWAVE_METADATA_*` env vars when the driver container starts. The driver publishes WebRTC offers with: | Offer field | Catalog value | Role | | ------------- | ------------- | ------------------------------------------------------------------ | | `sensor` | `"audio"` | Routing key (`sensors[].id`) | | `sensor_type` | `"audio"` | Matches `sensors[].type`; media-service classifies as **producer** | | `role` | `"producer"` | Active edge twin — publishes audio into the SFU | | `sender` | `"edge"` | Only edge may produce microphone traffic (TR-1.24) | Recording commands (`start_recording` / `stop_recording`) use `"sensor": "audio"` so they target the same stream identity as the live offer. ## Configuration | Variable | Default | Purpose | | ----------------------------------------- | --------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CYBERWAVE_METADATA_AUDIO_DEVICE` | `default` | Select an input by index, name fragment, or `default`. | | `CYBERWAVE_METADATA_ENABLE_AUDIO` | `true` | Enables WebRTC startup and reconnect. If `false`, no WebRTC audio or recording starts. Maps from `enable_audio` in the twin JSON. | | `CYBERWAVE_METADATA_ENABLE_RECORDING` | `true` | Gates the driver's fallback relay of `start_recording` / `stop_recording` (on the command topic) to the media-service. Does not affect `start_audio` / `stop_audio` (live stream is always allowed when `enable_audio=true`), and does not affect direct `webrtc-command` publishes from the frontend or Recorder node. Maps from `enable_recording` in the twin JSON. | | `CYBERWAVE_METADATA_AUTO_RECORDING_AUDIO` | `false` | When `true`, sets `recording: true` on the **initial** WebRTC offer so the media-service auto-starts recording at startup. After startup, recording is driven by explicit `start_recording` / `stop_recording`. Maps from `auto_recording_audio` in the twin JSON. | | `CYBERWAVE_METADATA_AUDIO_CHANNEL` | `audio/default` | Zenoh channel for raw audio chunks. | | `CYBERWAVE_METADATA_AUDIO_MIC_NAME` | `audio` | WebRTC `sensor` routing key (catalog `sensors[].id`). | | `CYBERWAVE_METADATA_AUDIO_SAMPLE_RATE` | `48000` | Capture sample rate (catalog standard). WebRTC output is always resampled to 48 kHz Opus. | | `CYBERWAVE_METADATA_AUDIO_CHANNELS` | `1` | Capture channels; auto-detection can upgrade to stereo. | When relaying a fallback recording command, the driver publishes the smallest payload the media-service needs (note `source_type: "edge"` here vs. `"tele"` for the frontend's REC button): ```json theme={null} { "command": "start_recording", "source_type": "edge", "sensor": "audio", "frontend_type": "audio" } ``` ```json theme={null} { "command": "stop_recording", "source_type": "edge", "sensor": "audio", "frontend_type": "audio" } ``` The media-service resolves the twin UUID from the MQTT topic and defaults the stream identity to `audio/live/default`. The same payload shape is used by the frontend audio widget's REC button and by the Recorder workflow node, so the three paths converge on the same media-service handler and the same ACK on `webrtc-command/status`. To run multiple microphones on one device, run multiple driver instances. Give each instance a different `CYBERWAVE_TWIN_UUID` and set `CYBERWAVE_METADATA_AUDIO_DEVICE` to the desired input. ## Linux Audio Notes The driver image installs `libportaudio2`, which gives `sounddevice` access to PortAudio's ALSA backend. If the host routes audio through PulseAudio or PipeWire, also make the relevant Pulse/PipeWire socket and client libraries available to the container. The driver logs all input devices at startup and publishes selected-device metadata to the twin. Set `CYBERWAVE_LOG_LEVEL=DEBUG` to see raw environment values and the resolved microphone configuration. ## macOS Notes Docker Desktop cannot pass CoreAudio into Linux containers. Cyberwave mirrors the camera MJPEG workaround: host ffmpeg captures AVFoundation audio and serves raw PCM over HTTP; the driver inside Docker reads that URL via `AudioBridgeCapture`. | Step | Command / artifact | | -------------- | ------------------------------------------------------------------ | | Install bridge | `cyberwave edge install` or `--reconfigure-microphone` | | Per-twin map | `~/.cyberwave/audio_streams.json` | | Container env | `CYBERWAVE_METADATA_AUDIO_DEVICE=http://host.docker.internal:8101` | | Recovery | `cyberwave edge restart` (kickstarts silent ffmpeg LaunchAgents) | Grant microphone permission when macOS prompts the terminal running ffmpeg. For local debugging without Docker, use `./run-local.sh` (direct `sounddevice` / PortAudio). ## Edge Cases * No audio devices at startup: the driver enumerates devices and fails configuration if none are available. Publishing a microphone sensor-failure alert before retrying with backoff is the expected runtime behavior. * Device disconnected mid-stream: the Linux/macOS device monitor detects add/remove events. The expected behavior is to stop WebRTC, publish a sensor-failure alert, and reconnect when the device returns. * Docker access: prefer `/dev/snd` plus the `audio` group; use privileged mode only when host audio permissions require it. * Cloud STT URL expiry: use signed URLs with enough TTL for queued workloads, or inline `audio_base64` for small files. * Large STT inputs: keep Whisper jobs below roughly `25 MB`; oversized inputs should fail with a clear validation error. ## Dual Audio Streaming Paths The driver streams captured audio on two independent, parallel paths: | Path | Output rate | Resampling | Metadata | Consumer | | ------------------- | --------------- | ------------------------- | ----------------------------------------------------------------- | ----------------------- | | **WebRTC** (Opus) | 48 kHz (always) | Yes, if hardware ≠ 48 kHz | `stream_attributes.sample_rate` in MQTT offer | Frontend, media service | | **Zenoh** (raw PCM) | Hardware native | **Never** | `sample_rate_hz`, `channels`, `encoding`, `layout` in wire header | `@cw.on_audio` workers | ### WebRTC path Audio is resampled to 48 kHz (the Opus codec's internal rate) before entering the WebRTC queue. The `stream_attributes` field in the MQTT `webrtc-offer` payload includes the actual `sample_rate` used, so the media service and frontend can verify compliance. The media service router uses standard mediasoup Opus negotiation — no custom validation is needed. ### Zenoh path Raw PCM chunks are published at the hardware's native capture rate with **no resampling**. On the first publish, the Zenoh wire header carries metadata: ```json theme={null} { "sample_rate_hz": 32000, "channels": 1, "encoding": "pcm_s16le", "layout": "mono" } ``` `@cw.on_audio` workers receive this metadata so they can correctly interpret the raw audio bytes. ### Parallelism The PortAudio callback places raw audio into a zero-copy swap buffer for Zenoh (O(1)) and queues resampled audio for WebRTC. Three threads run in true parallel: PortAudio capture, Zenoh publisher, and WebRTC streamer. ### Edge health (`edge_health`) The driver delegates `edge_health` to the SDK's `MicrophoneAudioStreamer`. Once WebRTC is connected, each heartbeat includes `streams.stream.stream_config` with `kind: "audio"`, `sample_rate_hz`, `channels`, and `codec: "opus"`. The block intentionally omits `source` (no host device path on the wire). Liveness uses `mark_alive`, so `fps` and `frames_sent` stay at zero for audio rows. The dashboard renders sample rate and channel layout from this block; workflow triggers still read Zenoh PCM, not MQTT health. ### Twin metadata The driver publishes both rates to the twin metadata under `audio_device`: | Field | Description | | --------------------- | ------------------------------------------------ | | `capture_sample_rate` | Hardware native rate (e.g. 32000) | | `stream_sample_rate` | WebRTC output rate (48000 when resampling is on) | | `channels` | Channel count | | `layout` | `"mono"` or `"stereo"` | | `software_resampling` | Whether resampling is active | ## Success Checks * `docker compose up` with a USB microphone streams audio to the microphone twin. * Frontend MQTT `start_audio` / `stop_audio` toggles the live WebRTC audio producer (no recording side effect); the driver replies with `audio_started` / `audio_stopped` on the matching status topic. * Frontend MQTT `start_recording` / `stop_recording` on `webrtc-command` toggles persisted recording without disturbing the live stream; the media-service replies on `webrtc-command/status`. * Zenoh `audio/default` chunks are consumable by an `on_audio` worker hook at the hardware's native sample rate. * Startup logs list available devices; `CYBERWAVE_METADATA_AUDIO_DEVICE` selects a specific one. * USB disconnect and reconnect transitions through alert, reconnect, and alert resolution. For source-level details, see the [Generic Microphone Driver README](https://github.com/cyberwave-os/generic-microphone-driver). ## Related Downstream playback counterpart — same `sensor: "audio"` routing key, `sensor_type: "speaker"`, `role: "consumer"`. Publishes the same `start_recording` / `stop_recording` payload on `webrtc-command` from a workflow — converges on the same media-service handler as the audio widget's REC button and the driver's fallback relay. Workflow-side audio pipeline (Audio Track, VAD, Wake Word, STT). Consumes Zenoh PCM from this driver — orthogonal to the WebRTC + recording path documented here. # Native speaker driver Source: https://docs.cyberwave.com/feature-reference/edge/drivers/native-speaker-driver Set up the native Cyberwave generic-speaker driver for WebRTC audio playback, MQTT start/stop control, Zenoh cue subscription, and hot-plug recovery.

Cyberwave is in Private Beta.

Request early access to get access to the Cyberwave dashboard.

## What It Provides The native speaker driver runs on the edge device that has the speaker attached. It is the downstream/playback counterpart of the microphone driver — it **consumes** a WebRTC audio stream from the media-service, hands the decoded PCM to `sounddevice` / PortAudio, and plays it through the configured output device. It also subscribes to the workflow-emitted Zenoh cue channels so the device can play short status chimes from a bundled MP3 library. The driver lives at: ``` cyberwave-edge-runtime/runtime-services/drivers/native/cyberwave/generic-speaker/ ``` It mirrors the layout of `generic-microphone` and reuses the same `BaseAudioTrack` / `BaseAudioStreamer` SDK base classes — the speaker subclasses are `SpeakerAudioTrack(BaseAudioTrack)` and `SpeakerAudioStreamer(BaseAudioStreamer)` in `cyberwave.sensor.speaker`. ## Quick start ```bash theme={null} cd cyberwave-edge-runtime/runtime-services/drivers/native/cyberwave/generic-speaker cp .env.example .env # fill in CYBERWAVE_TWIN_UUID and (optionally) CYBERWAVE_SPEAKER_DEVICE docker compose -f docker-compose.local.yml up ``` On macOS, run bare-metal with `./run-local.sh` from the driver directory — Docker Desktop on macOS runs in LinuxKit and cannot expose `/dev/snd`, so playback must happen on the host so PortAudio can talk to CoreAudio. ## MQTT command surface (TR-1.26) | Topic | Payload | Notes | | -------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------- | | `cyberwave/twin/{uuid}/command` | `{"command":"start_speaker", ...}` | Starts the WebRTC consumer + opens the host `sounddevice.OutputStream`. | | `cyberwave/twin/{uuid}/command` | `{"command":"stop_speaker", ...}` | Stops the consumer and closes the audio device gracefully. | | `cyberwave/twin/{uuid}/start_speaker/status` | `{"status":"ok" \| "error", ...}` | ACK published by the driver. | | `cyberwave/twin/{uuid}/stop_speaker/status` | `{"status":"ok" \| "error", ...}` | ACK published by the driver. | The driver also mirrors the legacy `start_audio` / `stop_audio` verbs so existing integrations keep working. ## Zenoh cue contract (TR-1.17 / TR-1.18) The driver subscribes to two cue channels with `policy="latest"`: | Channel | Commands | File played | | ------------------------------ | ----------------------------------- | -------------------------------------- | | `commands/recording_signaling` | `start_recording`, `stop_recording` | `sounds/general/recording_signal.mp3` | | `commands/assistant_signaling` | `start_assistant` | `sounds/assistant/start-assistant.mp3` | | `commands/assistant_signaling` | `stop_assistant` | `sounds/assistant/end-assistant.mp3` | Payloads are the standard Cyberwave envelope (`HeaderTemplate` + JSON body). The driver dedups identical `(channel, command)` pairs inside a 250 ms window, matching the browser-side handler. ## Standard catalog sensor configuration The standard Cyberwave catalog speaker asset declares one sensor block. `id` and `name` are `"audio"` (same routing key as the [native microphone driver](/feature-reference/edge/drivers/native-microphone-driver)); `type` is `"speaker"` (passive consumer). ```json theme={null} { "id": "audio", "name": "audio", "type": "speaker", "parent_link": "generic_speaker_link", "parameters": { "audio_device": "default", "audio_source": "webrtc", "audio_volume": "0.8", "audio_channels": "2", "enable_speaker": "true", "audio_bit_depth": "16", "audio_sample_rate": "48000", "auto_play_on_boot": "false" } } ``` Edge-core maps `parameters` → `CYBERWAVE_METADATA_*` env vars. The driver publishes WebRTC offers with: | Offer field | Catalog value | Role | | ------------- | ------------- | ------------------------------------------------------------------ | | `sensor` | `"audio"` | Routing key (`sensors[].id`) — shared with mic twins | | `sensor_type` | `"speaker"` | Matches `sensors[].type`; media-service classifies as **consumer** | | `role` | `"consumer"` | Passive twin — receives audio from the SFU | | `sender` | `"edge"` | Edge driver consumes the mixed downstream leg | ## Media-service contract (TR-1.21 / TR-1.22 / TR-1.24) WebRTC offers carry `sensor` (routing id), `sensor_type` (catalog `type`), and `role`. The media-service classifies offers before dispatch: | Sensor type | Role | Allowed sender | | ---------------------------------------------------------------------- | --------------------- | --------------------------------------- | | `audio`, `mic`, `microphone`, `audio_in`, `audio_mono`, `audio_stereo` | Producer (upstream) | `edge` only | | `speaker`, `loudspeaker`, `speakerphone`, `audio_out` | Consumer (downstream) | `edge` (driver) or `frontend` (preview) | Catalog standard pairs: microphone `sensor_type: "audio"` + `role: "producer"`; speaker `sensor_type: "speaker"` + `role: "consumer"`. Both use `sensor: "audio"`. Offers that conflict with this contract are rejected (error answer on `webrtc-answer`). Raw microphone traffic stays inside the media-service — only the speaker consumer leg is fanned out to edge/frontend peers. ## Configuration (`CYBERWAVE_*` env vars) | Variable | Default | Meaning | | -------------------------------------- | --------------- | ------------------------------------------------------------------ | | `CYBERWAVE_TWIN_UUID` | required | UUID of the speaker twin. | | `CYBERWAVE_SPEAKER_DEVICE` | `default` | Output device — integer index, name substring, or `default`. | | `CYBERWAVE_METADATA_AUDIO_SAMPLE_RATE` | `48000` | Sample rate of the speaker stream. | | `CYBERWAVE_METADATA_AUDIO_CHANNELS` | `2` | Channel count (1 = mono, 2 = stereo, up to 8). | | `CYBERWAVE_METADATA_AUDIO_BIT_DEPTH` | `16` | 16, 24, or 32 bit PCM. | | `CYBERWAVE_METADATA_AUDIO_VOLUME` | `0.8` | Master volume (0.0 – 1.0). Matches catalog standard-speaker asset. | | `CYBERWAVE_METADATA_SPEAKER_NAME` | `audio` | WebRTC sensor routing id (catalog `sensors[].id`). | | `CYBERWAVE_METADATA_AUDIO_SOURCE` | `webrtc` | Playback source: `webrtc`, `file`, `queue`, or `both`. | | `CYBERWAVE_METADATA_ENABLE_SPEAKER` | `true` | Gate speaker output without tearing down the driver. | | `CYBERWAVE_METADATA_AUTO_PLAY_ON_BOOT` | `false` | Auto-issue `start_speaker` on boot. | | `CYBERWAVE_METADATA_AUDIO_CHANNEL` | `audio/default` | Zenoh data-bus channel for parallel raw PCM publishing. | Nothing about the device, sample rate, channel count, or routing target is hard-coded — every value flows through env vars, runtime device discovery, or the twin metadata `audio_device` block. ## Cross-platform behaviour * **Linux** — ALSA direct pass-through via `/dev/snd` and `--group-add audio`. All discovery uses `sounddevice.query_devices()`; on `pyudev`-capable hosts, hot-plug events come from udev. * **macOS** — Bare-metal CoreAudio (no Docker), with full in-container DSP (volume, per-channel gain, channel routing matrix) applied before audio leaves the Python process. PulseAudio-CoreAudio bridging is a documented fallback for power users. ## Hot-plug (TR-1.11 – TR-1.13) Disconnecting the speaker triggers `AudioDeviceMonitor`, which reopens the SFU consumer leg + `sounddevice.OutputStream` against the new device — even when the replacement reports a different channel count or sample rate. The driver re-resolves the selected device against twin metadata on every recovery cycle and publishes `SPEAKER_FAILURE` / resolution alerts as the hardware comes and goes. ## SDK helpers The driver delegates everything to `cyberwave.sensor.speaker`: * `SpeakerAudioStreamer` — WebRTC + MQTT lifecycle (subclasses `BaseAudioStreamer`) * `SpeakerAudioTrack` — minimal upstream track required by the WebRTC SDP contract * `HostSpeakerCapture` — host `sounddevice.OutputStream` wrapper with file / queue / Zenoh sources * `play_file(...)`, `associate_speaker_to_microphone(...)`, `associate_speaker_to_microphones(...)` — high-level helpers from TR-1.25 See the [native microphone driver](/feature-reference/edge/drivers/native-microphone-driver) page for the upstream producer counterpart and the shared `sensor: "audio"` routing contract. # Navigation coordinate convention Source: https://docs.cyberwave.com/feature-reference/edge/drivers/navigation-coordinate-convention Cartesian and geodetic (GPS) coordinate frames in the shared navigation MQTT contract, and how drivers declare which they support. **Incremental convention.** Cartesian payloads remain fully compatible. The geodetic form is implemented by the DJI Wayline driver; other drivers opt in by declaring their navigation capabilities. ## Goal Cyberwave uses one navigation lifecycle for every autonomous asset: ```text theme={null} cyberwave/twin/{twin_uuid}/navigate/command cyberwave/twin/{twin_uuid}/navigate/status ``` The command topic, `action_id`, commands (`goto`, `path`, `stop`, `pause`, and `resume`), and status lifecycle are shared. What differs by asset is the coordinate representation: * Ground robots normally navigate in a Cartesian `map` frame, in metres. * GPS-native vehicles, such as a DJI aircraft executing a Wayline mission, navigate using latitude, longitude, and altitude. The coordinate representation must therefore be explicit in the command payload. A driver must never infer it from the robot model or from the numeric values. ## Proposed `coordinate_frame` New navigation payloads include a `coordinate_frame` object with a required `kind`. The coordinate values themselves do not contain unit suffixes: their units are declared once by the frame. | `kind` | Position field | Required frame fields | Intended assets | | ----------- | ------------------------------------------------------ | ---------------------------------------------------------------------- | -------------------- | | `cartesian` | `position: { x, y, z }` | `frame_id`, `linear_units: "m"` | Nav2 / ground robots | | `geodetic` | `geodetic_position: { latitude, longitude, altitude }` | `horizontal_units: "deg"`, `vertical_units: "m"`, `altitude_reference` | GPS mission vehicles | `coordinate_frame` is the single source of truth for units. Do not mix it with field names such as `latitude_deg` or `altitude_m`. ### Cartesian waypoint example ```json theme={null} { "command": "path", "action_id": "navigation-action-uuid", "coordinate_frame": { "kind": "cartesian", "frame_id": "map", "linear_units": "m", "yaw_units": "deg" }, "waypoints": [ { "position": { "x": 2.0, "y": 4.5, "z": 0.0 }, "yaw": 90.0 } ] } ``` `frame_id` identifies the local coordinate frame. The existing navigation anchor transform applies only to this representation. ### Geodetic waypoint example ```json theme={null} { "command": "path", "action_id": "navigation-action-uuid", "coordinate_frame": { "kind": "geodetic", "horizontal_units": "deg", "vertical_units": "m", "altitude_reference": "relative_to_takeoff", "yaw_units": "deg", "yaw_reference": "true_north" }, "waypoints": [ { "geodetic_position": { "latitude": 47.3769, "longitude": 8.5417, "altitude": 30.0 }, "orientation": { "heading": 90.0 } } ] } ``` For `geodetic`, latitude and longitude use standard GPS/WGS84 decimal degrees. For the first DJI implementation, altitude is measured relative to the takeoff point. `orientation.heading` is clockwise from true north (`0` = north, `90` = east). `yaw` remains accepted as a legacy input alias during migration, but the backend publishes the canonical `orientation` object. ### Single-target `goto` `goto` always means “reach one target”. Cartesian drivers receive the target in `position`; geodetic drivers receive it in `geodetic_position`: ```json theme={null} { "command": "goto", "action_id": "navigation-action-uuid", "coordinate_frame": { "kind": "geodetic", "horizontal_units": "deg", "vertical_units": "m", "altitude_reference": "relative_to_takeoff", "yaw_units": "deg", "yaw_reference": "true_north" }, "geodetic_position": { "latitude": 47.3769, "longitude": 8.5417, "altitude": 30.0 }, "orientation": { "heading": 90.0 } } ``` A DJI driver expands a geodetic `goto` into an internal two-point Wayline: its current GPS position followed by the requested target. It must reject the command when its current GPS position is unavailable. ## Compatibility and driver behaviour Existing Cartesian clients and drivers remain compatible. During migration, a payload without `coordinate_frame` is treated as the legacy Cartesian representation and follows the existing frame-transform behaviour. Drivers declare the coordinate kinds they support. A driver must reject a command whose `coordinate_frame.kind` it does not support and publish a `failed` response on `navigate/status` using the received `action_id`. A geodetic payload must never be passed through a Cartesian navigation-anchor transform. Conversely, a Cartesian payload must not be treated as GPS merely because it targets a GPS-capable vehicle. ## Orientation capabilities `capabilities.navigation.orientation` tells clients which target-orientation members a hardware profile can actually command, and which are owned by the provider. For the DJI Mini 4 Pro Wayline profile: ```json theme={null} { "coordinate_frames": ["geodetic"], "orientation": { "commandable": ["heading"], "provider_managed": ["roll", "pitch"], "heading_reference": "true_north" }, "requires_runtime_wayline_probe": true } ``` This is a static hardware profile, not an availability result. The separate Wayline probe reports whether the connected aircraft/firmware is currently `READY`, `NOT_SUPPORTED`, or `INCONCLUSIVE`. A UI should expose only the commandable fields; the driver remains the final validation boundary. ## Implementation scope Implementing this convention requires coordinated changes to the backend navigation schema and service, driver capability metadata, and each supporting driver. Workflow authoring is intentionally separate: a future workflow node can select a coordinate representation based on the target driver's declared capabilities while continuing to use the same navigation topic and action lifecycle. # OpenArm (ROS 2) Source: https://docs.cyberwave.com/feature-reference/edge/drivers/openarm-ros2 Set up an OpenArm bimanual robot for the first time and connect it to Cyberwave as a ROS 2 edge driver — CAN bus, ROS 2 Humble, Docker, and MQTT mode switching. [OpenArm](https://docs.openarm.dev) is an open-source bimanual manipulator. On Cyberwave it runs as a **ROS 2 edge driver** built on [`BaseROS2Driver`](/feature-reference/edge/drivers/ros2-base-driver): the driver forwards joint feedback into Cyberwave over MQTT and accepts teleop/planning commands back from the cloud. This page has two parts: 1. **First-time hardware setup** — bring the physical arm up on its edge computer (mostly the [official OpenArm docs](https://docs.openarm.dev)). 2. **Connect to Cyberwave** — register the driver on a twin and stream it into the platform. If you only need the driver framework (lifecycle, `from_ros` forwarding, hooks), read [`BaseROS2Driver`](/feature-reference/edge/drivers/ros2-base-driver) first. This page is the hardware- and platform-specific wrapper around it. *** ## Part 1 — First-time OpenArm setup Follow the official [OpenArm Setup Guide](https://docs.openarm.dev/software/setup/) as the source of truth. The steps below summarize the path validated on Cyberwave edge hardware. ### 1. Edge computer The reference edge computer is an **NVIDIA Jetson Orin Nano** on **JetPack 6.x**: * JetPack 6 is built on **Ubuntu 22.04 LTS** → use **ROS 2 Humble** (the native distro for 22.04). * Flash the [official JetPack SD card image](https://developer.nvidia.com/embedded/learn/get-started-jetson-orin-nano-devkit#write) with Etcher, then update the base system: ```bash theme={null} sudo apt update && sudo apt upgrade -y sudo apt install -y curl git build-essential python3-pip ``` For heavy on-device AI work, unlock max clocks with `sudo nvpmodel -m 0 && sudo jetson_clocks`. ### 2. Wiring and power Follow the OpenArm [Power & CAN wiring guide](https://docs.openarm.dev/hardware/wiring-and-casing-guide/power-can). Each arm communicates over a **CAN FD** bus; a bimanual setup uses two CAN channels (one per arm), and leader–follower teleop uses up to four. ### 3. CAN bus Install CAN tooling from the OpenArm PPA: ```bash theme={null} sudo add-apt-repository -y ppa:openarm/main sudo apt update sudo apt install -y can-utils iproute2 openarm-can-utils ``` Bring each interface up in **CAN FD** mode (1 Mbps arbitration / 5 Mbps data): ```bash theme={null} sudo ip link set can0 down sudo ip link set can0 type can bitrate 1000000 dbitrate 5000000 fd on sudo ip link set can0 up ``` Repeat for `can1` (and `can2`/`can3` for leader–follower). Verify traffic: ```bash theme={null} ip -br link | grep '^can' # interfaces up? candump can0 # watch bus traffic ``` USB‑CAN adapters can enumerate in a different order across reboots or USB ports, which swaps `can0`/`can1`. If the arms behave as if mirrored, re-seat the adapters in a known plug-in order and re-verify. Adapter driver setup on Jetson (e.g. PEAK) can require extra kernel steps — see the [OpenArm CAN docs](https://docs.openarm.dev/software/setup/). ### 4. Verify the motors Confirm each joint answers on its CAN ID (response ID = command ID + `0x10`): ```bash theme={null} # Terminal 1 candump can0 # Terminal 2 — ping motor #1 cansend can0 001#0102030405060708 # expect a reply on 011 ``` The OpenArm [motor setup docs](https://docs.openarm.dev/software/setup/) cover motor ID assignment and baudrate changes. Motor parameters have a limited write budget — do **not** run baudrate/ID scripts repeatedly. ### 5. ROS 2 Humble + OpenArm packages Install ROS 2 Humble ([official instructions](https://docs.openarm.dev/software/ros2/install/)), then the OpenArm ROS 2 stack: ```bash theme={null} sudo apt install -y ros-humble-ros-base python3-colcon-common-extensions # OpenArm workspace mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src git clone https://github.com/enactic/openarm_description.git git clone https://github.com/enactic/openarm_ros2.git cd ~/ros2_ws && colcon build --symlink-install source install/setup.bash ``` At this point you have a working, ROS 2–controllable OpenArm. Everything below connects it to Cyberwave. *** ## Part 2 — Connect to Cyberwave Cyberwave ships the OpenArm driver as a **Docker image** managed by [Edge Core](/feature-reference/edge/overview). The driver: * streams `/joint_states` and telemetry into Cyberwave MQTT (`source_type: edge`), * accepts controller assignments (teleop / planning) from the cloud, * hot-switches between **local operation** (physical leader arm drives the follower) and **remote operation** (cloud/teleop drives the arm) without restarts. ### Prerequisites 1. A **twin** for the OpenArm in your Cyberwave environment (created from the OpenArm catalog asset). 2. A Cyberwave **API key** for that workspace. 3. Edge Core installed on the arm's edge computer — see [Cyberwave Edge](/feature-reference/edge/overview). ### Register the driver on the twin Drivers are registered in a twin's `metadata.drivers` (Environment view → **Advanced editing**). See [Drivers → How to use drivers](/feature-reference/edge/drivers/overview#how-to-use-drivers) for the general pattern. ```json theme={null} { "drivers": { "default": { "docker_image": "cyberwaveos/openarm-driver", "version": "latest", "params": [ "--privileged", "--cap-add", "NET_RAW", "--cap-add", "NET_ADMIN", "--cap-add", "SYS_ADMIN", "--cap-add", "SYS_MODULE", "-v", "/dev:/dev", "-v", "/sys:/sys:rw", "-v", "/lib/modules:/lib/modules:ro", "-e", "OPENARM_ROBOT_ID=robot_openarm_v1" ] } } } ``` The elevated capabilities and `/dev`, `/sys`, `/lib/modules` mounts let the container manage the host CAN interfaces. Edge Core auto-injects `CYBERWAVE_API_KEY`, `CYBERWAVE_TWIN_UUID`, MQTT connection settings, and child-twin UUIDs — you do **not** put secrets in metadata. On Jetson, Edge Core auto-tries a `jetson-` image tag and can pass `--gpus`. See [Drivers → Platform-specific drivers](/feature-reference/edge/drivers/overview#platform-specific-drivers). ### Environment variables When running the container directly (for local debugging), supply the platform connection via env vars. Use placeholders — never commit real keys or UUIDs. ```bash theme={null} export CYBERWAVE_BASE_URL="https://api.cyberwave.com" export CYBERWAVE_MQTT_HOST="mqtt.cyberwave.com" export CYBERWAVE_MQTT_PORT=8883 export CYBERWAVE_API_KEY="" export CYBERWAVE_TWIN_UUID="" export CYBERWAVE_CHILD_TWIN_UUIDS="" # optional: bimanual sub-twins ``` Under Edge Core these are injected automatically from the edge credentials — the manual exports above are only for standalone `docker run` debugging. ### Run the container (standalone debug) ```bash theme={null} docker run \ --name openarm-driver \ --restart unless-stopped \ --network host --privileged \ --cap-add=NET_RAW --cap-add=NET_ADMIN --cap-add=SYS_ADMIN --cap-add=SYS_MODULE \ -e CYBERWAVE_BASE_URL -e CYBERWAVE_MQTT_HOST -e CYBERWAVE_MQTT_PORT \ -e CYBERWAVE_API_KEY -e CYBERWAVE_TWIN_UUID \ -e OPENARM_ROBOT_ID=robot_openarm_v1 \ -v /dev:/dev -v /sys:/sys:rw -v /lib/modules:/lib/modules:ro \ cyberwaveos/openarm-driver:latest ``` Once connected, the twin appears live in the Cyberwave UI and joint feedback streams in real time. ### Operation modes The OpenArm driver bridges Cyberwave [operation modes](/feature-reference/edge/drivers/base-driver-class#operation-modes-driveroperationmode) to the ROS 2 lifecycle: | Mode | Meaning | | -------------------- | ----------------------------------------------------------------------------------- | | **Local operation** | A physical leader arm drives the follower over CAN; Cyberwave observes and records. | | **Remote operation** | The cloud controller (teleop / planning) drives the arm. | | **Idle** | Node stays warm; joint feedback keeps streaming, no control. | A twin with **no controller assigned streams telemetry but stays idle** — assigning a controller in Cyberwave activates the matching mode. You can also switch modes by publishing a controller-change command to the twin's command topic: Set `CYBERWAVE_MQTT_USER` to your Cyberwave username — the `username` field from `GET /api/v1/users/@me/status/`, not your email address and not a twin UUID. The broker re-checks authorization periodically using only the username, so a value that matches no account works until that re-check and then starts failing. ```bash theme={null} # Switch to remote operation (cloud/teleop) mosquitto_pub -h mqtt.cyberwave.com -p 8883 --capath /etc/ssl/certs \ -u "$CYBERWAVE_MQTT_USER" -P "$CYBERWAVE_API_KEY" \ -t "cyberwave/twin/$CYBERWAVE_TWIN_UUID/command" \ -m '{"command":"controller-changed","controller":{"controller_type":"teleop"}}' # Switch to local operation (physical leader arm) mosquitto_pub -h mqtt.cyberwave.com -p 8883 --capath /etc/ssl/certs \ -u "$CYBERWAVE_MQTT_USER" -P "$CYBERWAVE_API_KEY" \ -t "cyberwave/twin/$CYBERWAVE_TWIN_UUID/command" \ -m '{"command":"controller-changed","controller":{"controller_type":"localop"}}' ``` Assigning a controller from the Cyberwave UI does the same thing without touching MQTT directly. *** ## Troubleshooting | Symptom | Likely cause / fix | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | No CAN interfaces (`ip -br link` empty) | Adapter driver not loaded or arm unpowered — see [OpenArm CAN docs](https://docs.openarm.dev/software/setup/). | | Arms behave mirrored / swapped | `can0`/`can1` enumerated in the wrong order — re-seat adapters in a known plug-in order. | | Motor gives no `candump` reply | Wrong CAN ID, bus not in CAN FD mode, or bitrate mismatch (must be 1 Mbps / 5 Mbps). | | Twin connects but no joint data | ROS 2 stack not reaching ACTIVE, or `/joint_states` not published — check the driver logs. | | Twin never appears in UI | Bad/absent `CYBERWAVE_API_KEY` or `CYBERWAVE_TWIN_UUID`, or MQTT host unreachable. | For lifecycle-level issues (hangs at *Waiting for ROS lifecycle ACTIVE*, missing `from_ros` forwards), see the [`BaseROS2Driver` troubleshooting table](/feature-reference/edge/drivers/ros2-base-driver#troubleshooting). *** ## Related The ROS 2 driver base this driver is built on. Registering drivers on a twin, platform keys, GPU. Installing Edge Core on the arm's edge computer. Hardware, wiring, CAN, and ROS 2 reference. # Drivers Source: https://docs.cyberwave.com/feature-reference/edge/drivers/overview A Cyberwave driver is a Docker image that interacts with device hardware and the Cyberwave backend. A Cyberwave driver is a Docker image that interacts with device hardware and the Cyberwave backend. ## How to use drivers Register a driver by adding its configuration to a twin's metadata (or the catalog twin's metadata if you control the catalog twin). Use the environment view's **Advanced editing** to edit metadata. Note: changing a catalog twin's metadata affects all subsequently created digital twins derived from that catalog twin. Example driver metadata (JSON): ```json theme={null} { "drivers": { "default": { "docker_image": "cyberwaveos/so101-driver", "version": "0.0.1", "params": ["--network", "local", "--add-host", "host.docker.internal:host-gateway"] } } } ``` ### Pin cameras and microphones by serial number When an edge host has multiple cameras or USB microphones of the same model, set the physical unit's serial at top-level `metadata.serial_number`. Keep it a JSON string so leading zeroes are preserved: ```json theme={null} { "serial_number": "046322252081", "drivers": { "default": { "docker_image": "cyberwaveos/camera-driver", "params": ["--device", "/dev/video0:/dev/video0"] } } } ``` `serial_number` names one physical unit. Camera `video_device` and microphone `audio_device` fields instead name a capture source or selector. A serial takes precedence, and the driver fails rather than silently substituting different hardware when the pinned unit is missing. On Linux, Edge Core automatically bind-mounts `/dev/v4l` into camera-driver containers when that host directory exists, allowing UVC serials to resolve through `/dev/v4l/by-id`. It similarly exposes `/dev/snd` to the generic audio drivers. Custom launchers must provide those mounts themselves. **stub** — `cyberwave edge install` does not ask you to pick a `/dev/videoN` for a camera twin that already sets `serial_number`; it matches the serial against the attached cameras and binds them for you. Twins without one are still asked, and the camera you pick is saved back as that twin's `serial_number`, so the question is asked once per camera rather than on every install. When a pinned serial matches no attached camera the installer warns and falls back to asking, because substituting another camera would stream the wrong footage. **stub** — Cameras that publish no USB serial (the Logitech C920 is one) can never be pinned with `serial_number`. Set `metadata.video_device` to a udev stable name instead — `/dev/v4l/by-id/...` or `/dev/v4l/by-path/...` — and the installer binds the twin without asking, exactly as it does for a serial. `by-id` follows the camera across ports; `by-path` follows the port. An `rtsp://` or `http://` URL marks a network camera, which is also never asked about and takes no local device. A bare index or `/dev/videoN` is positional, not identity, so those twins are still prompted. ### GPU passthrough Drivers can opt-in to GPU acceleration by setting `"prefer_gpu": true` in their metadata. When the host has the NVIDIA container runtime available **and** configured as the default in `/etc/docker/daemon.json`, Edge Core passes `--gpus` to the driver container. The optional `"gpu"` field controls which GPUs are exposed: | `gpu` value | Docker flag | Use case | | -------------- | --------------------- | ---------------------------- | | *(not set)* | `--gpus all` | All available GPUs (default) | | `1` | `--gpus 1` | Limit to 1 GPU | | `"device=0,2"` | `--gpus "device=0,2"` | Specific GPU devices | ```json theme={null} { "drivers": { "default": { "docker_image": "cyberwaveos/go2-ros2-driver:humble", "prefer_gpu": true, "gpu": "all" } } } ``` On NVIDIA Jetson devices, Edge Core auto-detects the platform and tries a `jetson-` prefixed image tag (e.g. `:humble` → `:jetson-humble`), falling back to the original if unavailable. You can also add a `"linux-aarch64-jetson"` driver key in metadata for explicit Jetson-specific configuration. ### Platform-specific drivers Use platform keys in `metadata.drivers` to provide platform-specific images or params: ```json theme={null} { "drivers": { "default": { "docker_image": "cyberwaveos/driver:humble" }, "linux-aarch64-jetson": { "docker_image": "cyberwaveos/driver:jetson-humble", "prefer_gpu": true }, "darwin-arm64": { "docker_image": "cyberwaveos/driver:humble", "params": ["--add-host", "host.docker.internal:host-gateway"] } } } ``` Edge Core resolves drivers in order: `linux-aarch64-jetson` → `linux-aarch64` → `linux` → `default`. Manage edge driver containers: | Subcommand | Description | | ---------- | -------------------------------------------------------- | | `list` | List running driver containers (`--all` includes exited) | | `start` | Start a stopped driver container | | `stop` | Stop a running driver container | ## Multi-container drivers Some robots require multiple cooperating containers — for example a ROS 2 driver, bridge nodes, Nav2, SLAM, and elevation mapping. Use the `services` array in driver metadata to define a multi-container stack that Edge Core launches automatically. ```json theme={null} { "drivers": { "linux-aarch64-jetson": { "services": [ { "image": "cyberwaveos/go2-ros2-driver:jetson-humble", "name": "driver", "command": ["ros2", "launch", "cyberwave_go2_driver", "robot_driver.launch.py"] }, { "image": "cyberwaveos/go2-ros2-driver:jetson-humble", "name": "bridges" }, { "image": "cyberwaveos/ros2-nav2:jetson-humble", "name": "nav2" }, { "image": "cyberwaveos/ros2-slam:jetson-humble", "name": "slam" }, { "image": "cyberwaveos/ros2-elevation-mapping:jetson-humble", "name": "elevation", "prefer_gpu": true } ], "shared_env": { "ROS_DOMAIN_ID": "0", "CYBERWAVE_MAP_DIR": "/data" }, "shared_params": ["--network", "host", "-v", "/data:/data"] }, "default": { "docker_image": "cyberwaveos/go2-ros2-driver", "prefer_gpu": true } } } ``` Key points: * `services` present → multi-container mode. `docker_image` present → single-container mode (existing behavior, unchanged). * Each service requires `image` (Docker image) and `name` (used in the container name suffix). * Optional per-service fields: `command`, `env`, `params`, `prefer_gpu`, `gpu`. * `shared_env` and `shared_params` apply to all services. Per-service `env` overrides shared values. * Container naming: `cyberwave-driver-{twin_uuid[:8]}-{service_name}`. * Edge Core injects standard env vars (`CYBERWAVE_API_KEY`, MQTT, Zenoh, etc.) into every service automatically. ## Data bus Drivers publish sensor data (frames, depth, joint states) to the **edge data bus** — a Zenoh-backed publish/subscribe system that lets worker containers consume data with zero network overhead (shared memory). See [Writing compatible drivers](/feature-reference/edge/drivers/writing-compatible-drivers) for the channel naming convention and wire format. ## macOS hardware bridge When Edge Core runs on macOS, Linux `--device` mappings in Docker params cannot directly expose host camera/serial hardware to driver containers. Use a host bridge process and forward into Docker via `host.docker.internal`. * Optional host hook env var: * `CYBERWAVE_MACOS_DEVICE_BRIDGE_COMMAND` * Command template variables: * `{host_device}`, `{container_device}`, `{twin_uuid}`, `{container_name}`, `{config_dir}` * Bridge command can return a resolved source (`resolved_device=...` or JSON) so Edge Core can inject `CYBERWAVE_METADATA_VIDEO_DEVICE` automatically. * Optional macOS behavior: * `CYBERWAVE_MACOS_STRIP_VIDEO_DEVICE_PARAMS=true` removes Linux-only `--device /dev/video*` mappings before container start when a non-`/dev` source is resolved. * For camera twins, Edge Core can derive default macOS camera bridge candidates even without explicit `--device` params, enabling minimal default driver metadata to work. * Use platform-specific driver keys in `metadata.drivers` (for example `darwin-arm64`, `darwin`, `macos`) to provide macOS-specific params while keeping `default` for Linux. # BaseROS2Driver (ROS 2) Source: https://docs.cyberwave.com/feature-reference/edge/drivers/ros2-base-driver Reference for cyberwave.driver.ros2.BaseROS2Driver — dual Cyberwave + rclpy lifecycle, from_ros MQTT forwarding, hooks, env vars, and UR Sim lab. ## What `BaseROS2Driver` is `BaseROS2Driver` (`cyberwave.driver.ros2`) combines: * **`BaseDriver`** — Cyberwave API/MQTT, twin binding, interface registry, lifecycle alerts, `driver_info` telemetry * **`rclpy.lifecycle.Node`** — standard ROS 2 lifecycle transitions Import: ```python theme={null} from cyberwave.driver.ros2 import BaseROS2Driver, Ros2TopicSpec ``` **Typical goal:** stream ROS topics (joint states, odometry, custom msgs) into Cyberwave MQTT with **minimal driver code** — often **under 100 lines** for a forward-only bridge. Reference: [`ursim_driver.py`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-sdks/cyberwave-python/examples/ursim_driver.py). *** ## Process architecture (two event loops) `BaseROS2Driver.run()` is **not** a plain `BaseDriver.run()`: | Thread / loop | Role | | ---------------------------- | ------------------------------------------------------------------------------------------------------- | | **Main thread** | `MultiThreadedExecutor.spin_once()` — rclpy lifecycle, ROS subscriptions, `tick()` timer | | **Background daemon thread** | Dedicated **asyncio** loop running **`run_async()`** — Cyberwave connect, MQTT wire, `_tick_loop_async` | ROS callbacks (e.g. `/joint_states`) run on the executor thread; they **`asyncio.run_coroutine_threadsafe`** into the driver loop to publish MQTT without blocking rclpy. ```text theme={null} main() ├─ _start_driver_loop() # asyncio thread ├─ run_coroutine_threadsafe(run_async) └─ executor.spin_once() loop # ROS lifecycle + subscriptions ``` *** ## The ROS 2 lifecycle (managed) node `BaseROS2Driver` is a **ROS 2 managed node** — it subclasses `rclpy.lifecycle.Node` (a *LifecycleNode*) rather than a plain `rclpy.node.Node`. A managed node does not start doing work the moment it is constructed; it advances through an explicit, tool-controllable state machine so an orchestrator (or, here, the Cyberwave lifecycle) can bring hardware up and down deterministically. **The four primary states** (ROS 2 design REP-2007): | State | Meaning | Cyberwave hook that runs entering it | | ---------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | **Unconfigured** | Node exists; nothing allocated | — (just constructed) | | **Inactive** | Configured but **not** processing — publishers exist but are deactivated, params declared | `configure()` (on the `configure` transition) | | **Active** | Fully operational — callbacks fire, data flows | `connect_to_device()` → `register_callbacks()` → `activate()` (on the `activate` transition) | | **Finalized** | Terminal; node is being destroyed | `shutdown()` | **Transitions** (the verbs that move between states) are where your code runs. rclpy calls a `on_(state)` method for each; returning `SUCCESS` advances the state, `FAILURE`/`ERROR` does not: ```text theme={null} configure activate Unconfigured ───────▶ Inactive ───────────▶ Active ◀─────── ◀─────────── cleanup deactivate (any state) ──── shutdown ────▶ Finalized ``` Key consequences for driver authors: * **`create_publisher` on a LifecycleNode returns a *lifecycle* publisher** that only actually transmits while the node is **Active**. Publishing in `Inactive` is silently dropped — this is by design, not a bug. * **rclpy owns the `on_configure(state)` / `on_activate(state)` / `on_deactivate(state)` / `on_shutdown(state)` methods.** You must not redefine them with a different signature — that is exactly why Cyberwave exposes the prefix-dropped `configure()` / `activate()` / … hooks (see *Why hook names drop the `on_` prefix* below). * **Who triggers transitions?** Either an external lifecycle manager (`ros2 lifecycle set configure`) or, more commonly here, the driver itself when **`CW_ROS2_AUTO_ACTIVATE=true`** (it calls its own `~/change_state` service after the cloud connect). Without auto-activate the node sits in *Unconfigured* until something activates it. * **`on_cleanup` is treated as fatal** in this base — recovering an edge device in-process is unreliable, so the container is expected to restart to reconfigure (see the transition table below). This managed-node machine is the **ROS half** of the picture. It runs in parallel with the **Cyberwave** lifecycle (`DriverLifecycleState`), and the two are coordinated — that coordination is the next section. *** ## Two lifecycles — who calls what You maintain **two parallel state machines**. They are **ordered**: Cyberwave connect and `on_configure` run **before** the driver waits for ROS **ACTIVE**; MQTT + `from_ros` wiring runs **after** ROS activate signals ready. ```mermaid theme={null} sequenceDiagram participant Async as asyncio run_async participant ROS as rclpy lifecycle participant CW as Cyberwave MQTT Async->>Async: CONFIGURING / connect cloud Async->>Async: on_configure (no-op default) opt CW_ROS2_AUTO_ACTIVATE=true Async->>ROS: configure → activate (service client) end ROS->>ROS: on_configure: manifest params, configure() ROS->>ROS: on_activate: connect_to_device, register_callbacks, activate() ROS->>Async: _signal_ros_active() Async->>Async: wait _ros_active Async->>Async: CONNECTING / INACTIVE hooks Async->>CW: _wire_interface_from_registry Async->>ROS: wire_ros_publishers (from_ros subs) Async->>Async: ACTIVE + tick loop Note over ROS: tick() timer on ROS side Note over Async: on_tick on Cyberwave side ``` ### Cyberwave side (`run_async` — do not override) | Step | `DriverLifecycleState` | Async hook (mixin) | Your ROS sync hook? | | ------------------- | ---------------------- | ------------------------------------------------------------- | ------------------------------------------------------ | | Cloud connect | `CONFIGURING` | — | — | | After MQTT | `CONFIGURING` | `on_configure` → `_run_after_cloud_connect` (default no-op) | Use **`configure()`** in rclpy `on_configure` | | Auto-activate timer | — | `_begin_auto_activate` if env set | Triggers ROS configure→activate | | Block | — | `_wait_for_ros_active` (up to 300s) | ROS **`on_activate`** must call `_signal_ros_active()` | | Device phase | `CONNECTING` | `on_connect_to_device` → no-op | **`connect_to_device()`** already ran in ROS activate | | Wire | `INACTIVE` | `on_register_callbacks` → no-op | **`register_callbacks()`** already ran | | MQTT + ROS | `INACTIVE` | `_wire_interface_from_registry` + **`wire_ros_publishers()`** | — | | Ready | `INACTIVE` | `on_activate` → no-op | **`activate()`** already ran | | Run | `ACTIVE` | `_tick_loop_async`, monitoring, reconnect | ROS **`tick()`** timer separate | ### ROS side (rclpy — do not override `on_configure(state)`, etc.) | rclpy callback | Calls (order) | Your override | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | `on_configure(state)` | declare manifest params → **`configure()`** | **`configure()`** | | `on_activate(state)` | base **`connect_to_device`** → yours → **`register_callbacks`** → **`activate`** → start ROS tick timer → **`_signal_ros_active`** | **`connect_to_device`**, **`register_callbacks`**, **`activate`** | | `on_deactivate(state)` | stop tick timer → **`deactivate()`** | **`deactivate()`** | | `on_shutdown(state)` | stop tick timer → **`shutdown()`** | **`shutdown()`** | | `on_cleanup` | **FAILURE** — restart container to reconfigure | — | *** ## Why hook names drop the `on_` prefix `rclpy.lifecycle.Node` already defines **`on_configure(state)`**, **`on_activate(state)`**, … with a **state argument**. A no-arg `def on_configure(self)` in your subclass would **break** ROS lifecycle. | C++ / conceptual hook | Python method on your class | | ------------------------- | ------------------------------------------------- | | `on_configure()` | **`configure()`** | | `on_connect_to_device()` | **`connect_to_device()`** | | `on_register_callbacks()` | **`register_callbacks()`** | | `on_activate()` | **`activate()`** | | `on_deactivate()` | **`deactivate()`** (default no-op) | | `on_tick()` | **`tick()`** (ROS timer, not Cyberwave `on_tick`) | | `on_shutdown()` | **`shutdown()`** | Cyberwave **`on_configure`**, **`on_connect_to_device`**, … still exist on the class for `BaseDriver`’s ABC, but **`BaseROS2Driver`** routes them through **`_BaseDriverAsyncHooks`** — you normally **do not** implement them for forward-only drivers. Event hooks **keep** `on_` where there is no conflict: **`on_topic_name_changed(topic_entry, new_name)`**. *** ## Required vs optional (checklist) ### Minimum for ROS → Cyberwave streaming (UR Sim style) | Item | Required? | | ----------------------------------------------------------------------------- | ------------------------------ | | Subclass **`BaseROS2Driver`** | Yes | | **`REGISTRY_ID`** matching catalog asset | Yes (manifest + auto-register) | | **`define_interface`** with `add_publisher(..., from_ros=Ros2TopicSpec(...))` | Yes | | **`CallbackGroup()`** with **no** callback for auto `JointState` serialize | Typical for joints | | **`configure` / `connect_to_device` / `activate`** | May be empty `pass` / log only | | **`CW_ROS2_AUTO_ACTIVATE=true`** | Strongly recommended in dev | | **`CYBERWAVE_API_KEY`**, **`CYBERWAVE_TWIN_UUID`** | Yes at runtime | | ROS graph publishing the topic (e.g. `/joint_states`) | Yes | You do **not** need: * Manual MQTT `publish` loops for `from_ros` entries * Custom `JointState` → dict conversion (SDK default) * Overriding rclpy **`on_activate(state)`** * Implementing Cyberwave abstract **`on_configure`** async methods (mixin provides them) ### When you need more | Need | Implement | | ------------------------------------ | --------------------------------------------------------------------------------- | | Cyberwave command → ROS | `add_listener` + handler calling **`ros_publish(topic, msg)`** | | Custom payload shape | `CallbackGroup(callback=fn)` **with** `from_ros` — `fn(msg) -> dict` | | ROS params from YAML manifest | Ship **`manifest.yaml`** + `CW_DRIVER_MANIFEST` | | Runtime topic remaps | Manifest topic params + **`add_managed_publisher`** / **`on_topic_name_changed`** | | Periodic ROS work | **`tick()`** (uses ROS param **`tick_rate_hz`**, default 10 Hz) | | Periodic Cyberwave work | Override async **`on_tick()`** on `BaseDriver` path (same ACTIVE phase) | | Spawn a vendor `ros2 launch` | **`managed_launch`** in `define_node_manifest` | | Throttle a high-rate ROS stream | **`acquire_ros_stream_publish_slot(topic)`** | | Export ROS + MQTT manifest | **`write_manifest`** / `python main.py write-manifest` | | Hardware enable on controller assign | **`on_enter_teleop_*`** / **`on_controller_assigned`** | *** ## `define_interface` and `from_ros` ### `add_publisher` with ROS source ```python theme={null} from cyberwave.driver import CallbackGroup, DriverOperationMode, TopicSpec from cyberwave.driver.ros2 import Ros2TopicSpec iface.add_publisher( TopicSpec( topic_slug="cyberwave/joint/{twin_uuid}/update", payload_schema_ref="JointStatesPayload", description="Forward /joint_states", ), CallbackGroup(), # no Python callback — see serialization below from_ros=Ros2TopicSpec( topic="/joint_states", qos_depth=10, discovery_timeout_s=5.0, msg_type=None, # resolve from graph unless set (tests) ), operation_modes=frozenset(DriverOperationMode), ) ``` | Rule | Detail | | ---------------------------------------------- | -------------------------------------------------------------------- | | **`from_ros` only on `add_publisher`** | `add_listener` rejects `Ros2TopicSpec` | | **No `PublisherArgs.rate_hz` with `from_ros`** | Use **`TopicSpec.rate_hz`** on the topic spec to cap MQTT outbound | | **`operation_modes`** | Forwarders often use **all** modes: `frozenset(DriverOperationMode)` | ### What `wire_ros_publishers()` does at runtime 1. Lists registry entries with `from_ros` for current **`operation_mode`** 2. **`resolve_ros_message_class`** — polls ROS graph (or uses `msg_type=` override) 3. Creates **`create_subscription`** on the ROS topic 4. On each message: * If **no user callback** and type is **`sensor_msgs/msg/JointState`** → **`ros_joint_state_to_transport_payload`** * Else if user callback → must return **`dict`** * Else → **`ros_message_to_transport_payload`** (generic field flattening + `timestamp`, `source_type`) 5. **`run_coroutine_threadsafe`** → publish to resolved MQTT slug (and Zenoh if dual spec) Logs (throttled \~5s): * `ROS forward: /joint_states (sensor_msgs/msg/JointState) -> Cyberwave MQTT` * `ROS RX /joint_states: N message(s) — publishing to Cyberwave MQTT (6 joints)` ### Joint `/update` payload shape (default) **Flat** keys for Vector / twin telemetry compatibility: ```json theme={null} { "source_type": "edge", "shoulder_pan_joint": 0.12, "shoulder_lift_joint": -1.04, "timestamp": 1717000000.0, "velocities": { "shoulder_pan_joint": 0.01 }, "efforts": {} } ``` Nested `positions: { name: value }` is available via **`ros_joint_state_to_transport_payload(..., aggregated=True)`** if you supply a custom callback. ### Source-type convention Notice the `"source_type": "edge"` field above. This is the platform-wide convention every driver follows (full rules on the [BaseDriver page](/feature-reference/edge/drivers/base-driver-class#source-type-convention)): * **`from_ros` publishers stamp `edge`** automatically (physical feedback). When the driver runs against a simulator instead of hardware, publish **`sim`** instead. * **Command listeners** (`add_listener` + `ros_publish`) should accept teleop sources — **`tele`**, **`edit`**, **`sim_tele`** — and **must never act on `edge*`** messages, or the driver re-ingests its own joint feedback and fights itself. Declare the accepted set with `ProtocolArgs(source_types=[...])`. * Inbound messages **without** a `source_type` are treated leniently (accepted as commands) — not every producer stamps the field — but the `edge*` self-echo guard always applies. A topic registered as **both** a `from_ros` publisher (`edge`) and a command listener (`tele`/`edit`/`sim_tele`) — e.g. `joint/update` on an arm — is the canonical case where the `edge*` rejection matters. ### Arm drivers: mixin listener + `from_ros` publisher For a full manipulator stack, **do not** register `joint/update` yourself. Compose [driver mixins](/feature-reference/edge/drivers/driver-mixins). The **[Piper driver](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-edge-nodes/piper/piper_driver.py)** shows the full integration. | Registration | Owner | | ------------------------------------------------------ | ----------------------------------------------------------- | | `joint/update` listener (`tele` / `edit` / `sim_tele`) | `JointControllerMixin` (via `super().define_interface`) | | `twin/command` arm verbs | `ArmCapabilityMixin` (via `super().define_interface`) | | `joint/update` publisher (`edge`) | **Your** `define_interface` → `from_ros=Ros2TopicSpec(...)` | ```text theme={null} MQTT joint/update (tele) → JointControllerMixin → submit_joint_targets → inbox → tick() / pump_joint_commands → _publish_joint_command → ros_publish(cmd) MQTT twin/command → ArmCapabilityMixin → IK → same JointController path ROS joint_states_single → Ros2JointFeedbackMixin → _joint_states (IK, gripper latch) → from_ros forwarder → mqtt.publish @ rate_hz (edge) ``` **Critical:** `define_interface` must call `super().define_interface(iface)` **before** adding the `from_ros` publisher so mixin listeners are registered exactly once. *** ## Composing mixins on `BaseROS2Driver` See **[Driver mixins and capabilities](/feature-reference/edge/drivers/driver-mixins)** for the Piper walkthrough. Minimum integration for a teleoperable ROS arm: ```python theme={null} class PiperDriver( JointControllerMixin, ArmCapabilityMixin, Ros2JointFeedbackMixin, JointCommandBufferMixin, BaseROS2Driver, ): use_joint_controller = True use_joint_feedback = True use_base_commands = True def __init__(self, node_name: str, **kwargs): super().__init__(node_name, **kwargs) self._init_joint_feedback() self._init_joint_command_buffer() def define_interface(self, iface): super().define_interface(iface) iface.add_publisher( TopicSpec(namespace="joint", leaf="update", rate_hz=30.0, ...), CallbackGroup(), protocol=ProtocolArgs(source_types=[SOURCE_TYPE_EDGE]), from_ros=Ros2TopicSpec(topic="joint_states_single"), ) def tick(self): self.pump_joint_commands() ``` | Integration point | Why it matters | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | MRO: `JointControllerMixin` before `ArmCapabilityMixin` | Arm IK targets and MQTT teleop share `_apply_joint_targets` | | `_init_joint_feedback()` + `_init_joint_command_buffer()` in `__init__` | Allocates `_joint_states` and the thread-safe command inbox | | `super().define_interface` then `from_ros` publisher | Mixins own inbound catalog; driver owns outbound edge feedback | | `tick()` → `pump_joint_commands()` | Moves MQTT-thread targets onto the ROS executor via `_publish_joint_command` | | `joint_controller_motion() → None` | Passthrough when the vendor shapes motion in ROS (Piper vel/effort on `JointState`) | *** ## `CW_ROS2_AUTO_ACTIVATE` | Value | Behavior | | ----------------- | ----------------------------------------------------------------------------------------------------------------- | | **`true`** | After Cyberwave connect, driver calls lifecycle **`configure` → `activate`** via `~/change_state` service | | **unset / other** | Driver **blocks** in `_wait_for_ros_active` until something externally activates the node (or times out **300s**) | UR Sim example sets default in `main()`: ```python theme={null} os.environ.setdefault("CW_ROS2_AUTO_ACTIVATE", "true") ``` Without auto-activate you must run a lifecycle manager (`ros2 lifecycle set …`) **while** the executor is spinning. *** ## Operation modes drive the ROS lifecycle `BaseROS2Driver` ties Cyberwave [operation modes](/feature-reference/edge/drivers/base-driver-class#operation-modes-driveroperationmode) to ROS lifecycle transitions. When `_set_operation_mode` runs, the ROS enter-hooks request a `change_state` transition on this node: | Mode entered | ROS hook | ROS transition | | --------------- | -------------------------- | ----------------------------------------------- | | `NO_OP` | `on_enter_no_op()` | **DEACTIVATE** (node → inactive) | | `TELEOP_LOCAL` | `on_enter_teleop_local()` | **ACTIVATE** (configures first if unconfigured) | | `TELEOP_REMOTE` | `on_enter_teleop_remote()` | **ACTIVATE** | So a twin with **no controller assigned starts in `NO_OP`**: control is idle, but the node stays warm. Because `_set_operation_mode` is a no-op when the mode is unchanged, a forward-only bridge (no controller) never deactivates — it remains in its initial `NO_OP` and keeps streaming. **Edge ROS→Cyberwave forwarders are independent of operation mode.** `wire_ros_publishers()` runs as soon as ROS reaches ACTIVE, so `from_ros` joint/telemetry streams flow even in `NO_OP`. Declare them with `operation_modes=frozenset(DriverOperationMode)`. Override the enter-hooks (or `on_controller_assigned` / `on_controller_removed`) to add hardware enable/disable on top of the lifecycle transition — e.g. powering an arm when a controller attaches. *** ## Managed vendor launch (`managed_launch`) A driver can have the SDK **spawn and supervise a vendor `ros2 launch`** (e.g. a robot's stock bringup) as a child process, instead of you starting it separately. Declare it in `define_node_manifest()`: ```python theme={null} from cyberwave.driver.ros2.manifest import NodeManifest, ManifestManagedLaunch @classmethod def define_node_manifest(cls, node_name: str) -> NodeManifest: return NodeManifest( node_name=node_name, managed_launch=ManifestManagedLaunch( package="my_robot_bringup", launch_file="robot.launch.py", ros_setup="/opt/ros/humble/setup.bash", # this driver's ROS distro ros_overlay="", # vendor workspace overlay (or env) ), ) ``` At ROS `activate`, `ManagedRosLaunch` starts the child, waits for readiness, and stops it on shutdown. Setup scripts are sourced into the driver process so vendor message typesupport imports correctly. The SDK is distro-agnostic: it **does not** default a ROS distro or guess a workspace path. Setup scripts come only from the manifest (`ros_setup` / `ros_overlay`) and the `ROS_SETUP` / `ROS_SETUP_OVERLAY` env vars. Declare the distro path in your driver's manifest (it is vendor-specific), not in the SDK. *** ## ROS stream → Cyberwave rate limiting ROS sensor topics often exceed 100 Hz. The `from_ros` forwarder and any custom ROS callback throttle outbound Cyberwave publishes with a per-topic cap that inherits `BaseDriver`'s resolution (default **30 Hz**): | API | Purpose | | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ros_stream_publish_max_hz(ros_topic)` | Resolves the cap: per-publisher `TopicSpec(rate_hz=...)` → manifest `mqtt_max_hz:` → `BaseDriver.STREAM_PUBLISH_MAX_HZ` (default 30 Hz) — no separate ROS-only default | | `acquire_ros_stream_publish_slot(ros_topic, *, max_hz=None)` | `True` when a publish for that topic is due (latest-wins) | | `ros_stream_key(ros_topic)` | Stable throttle key (`ros:`) | ```python theme={null} def _on_joint_states(self, msg) -> None: if not self.acquire_ros_stream_publish_slot("/joint_states_single"): return # drop — arrived faster than the cap self.publish_to_cyberwave(msg) ``` This wraps `BaseDriver.acquire_stream_publish_slot` with a ROS-topic key. See [BaseDriver → Stream publish rate limiting](/feature-reference/edge/drivers/base-driver-class#stream-publish-rate-limiting). *** ## Combined manifest (ROS params + MQTT catalog) `BaseROS2Driver` exports a **single `manifest.yaml`** that merges the ROS node manifest (params, topics, `managed_launch`) with the compiled-from-code MQTT `cw-driver` catalog: | API | Returns | | --------------------------------------- | ------------------------------------------------------ | | `define_node_manifest(node_name)` | ROS node fields (override per driver) | | `get_combined_manifest(compiled=False)` | Merged ROS + MQTT dict | | `write_manifest(path=None)` | Writes `manifest.yaml` (defaults to `./manifest.yaml`) | Export it without running the driver — typically a CLI subcommand and a Docker build step: ```bash theme={null} python main.py write-manifest # writes ./manifest.yaml python main.py write-manifest out.yaml # explicit path ``` Do not hand-edit the result: change Python (`define_node_manifest` + `define_interface`) and re-export. At runtime, point the driver at it with `CW_DRIVER_MANIFEST`. *** ## Construction and entrypoint ```python theme={null} driver = UrSimDriver( node_name="ursim_driver", # or CW_ROS2_NODE_NAME manifest_path=None, # or CW_DRIVER_MANIFEST twin=None, # optional pre-bound twin auto_register_interface=None, # inherit class default True ) driver.run() ``` | Method | Role | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **`create()`** | `cls(CW_ROS2_NODE_NAME, CW_DRIVER_MANIFEST)` from env | | **`run()`** | Start asyncio thread + spin executor until `run_async` completes | | **`ros_publish(topic, msg)`** | Lazy `create_publisher` — call from **`tick()`** (executor thread); see the thread-affinity note under [Cyberwave → ROS](#cyberwave-ros-commands) | Node name / namespace can be overridden via ROS env helpers (`node_name_from_env`, `node_namespace_from_env`). *** ## Environment variables ### Cyberwave (inherited from `BaseDriver`) | Variable | Purpose | | --------------------- | ----------------- | | `CYBERWAVE_API_KEY` | API + MQTT auth | | `CYBERWAVE_TWIN_UUID` | Twin UUID | | `CYBERWAVE_BASE_URL` | API base | | `CYBERWAVE_MQTT_*` | Broker connection | Backend lifecycle alerts are **always** synced after connect (not env-configurable). Set **`REGISTRY_ID`** on the driver class (not via env). ### ROS 2 driver specific | Variable | Default | Purpose | | --------------------------- | ----------------------- | --------------------------------------------------------------------------------------- | | **`CW_ROS2_AUTO_ACTIVATE`** | unset | `true` → auto configure/activate | | **`CW_ROS2_NODE_NAME`** | `cyberwave_ros2_driver` | ROS node name | | **`CW_DRIVER_MANIFEST`** | none | Path to `manifest.yaml` (params + topic name params) | | **`ROS_DOMAIN_ID`** | `0` | Must match UR driver / sim | | **`ROS_SETUP`** | none | ROS underlay `setup.bash` sourced for `managed_launch` (overrides manifest `ros_setup`) | | **`ROS_SETUP_OVERLAY`** | none | Vendor workspace `setup.bash` overlay (overrides manifest `ros_overlay`) | | **`CW_MANAGED_LAUNCH_LOG`** | temp file | Path for the managed vendor launch's stdout/stderr | Manifest may declare **`tick_rate_hz`** ROS parameter (integer) — drives ROS-side **`tick()`** timer. Per-parameter overrides also follow the SDK `CW_ROS2_*` env convention. The SDK no longer defaults `ROS_SETUP` to a specific distro. For `managed_launch` drivers, set `ros_setup` in the manifest (recommended) or export `ROS_SETUP` / `ROS_SETUP_OVERLAY`. *** ## ROS hooks — what to put in each ### `configure()` * Parse non-hardware config, allocate buffers * **Do not** open device connections (that is **`connect_to_device()`**) * rclpy `on_configure` already declared manifest parameters ### `connect_to_device()` * Open robot/sim connection if needed * For UR Sim + `ur_robot_driver`, often **empty** — another node publishes `/joint_states` ### `register_callbacks()` * Device-native ROS subscriptions **not** covered by `from_ros` * Example: subscribe to a custom diagnostic topic with a Python callback ### `activate()` * Create ROS publishers you control manually * Start control loops * **`from_ros` wiring happens after** this in `run_async` — do not rely on MQTT forwards during `activate()` itself ### `tick()` * Fast periodic work on ROS timer * Exceptions are logged; timer keeps running ### `shutdown()` * Destroy publishers/subscriptions you created * Complement ROS `on_shutdown` transition *** ## Cyberwave → ROS (commands) ```python theme={null} def define_interface(self, iface): iface.add_listener( TopicSpec(topic_slug="cyberwave/twin/{twin_uuid}/command"), CallbackGroup(callback=self._on_cmd), command=CommandArgs(name="my_cmd"), ) def _on_cmd(self, envelope: dict) -> None: from std_msgs.msg import String self.ros_publish("/my_ros_topic", String(data="...")) ``` `ros_publish` caches publishers per `(topic, msg_type)`. **Thread affinity.** MQTT listener callbacks run on the **asyncio loop thread**, but rclpy node operations (`create_publisher`, `publish`, `create_subscription`, `get_clock`) belong on the **executor thread** ([two event loops](#process-architecture-two-event-loops)). Calling `ros_publish` directly from a listener works for one-shot, low-rate commands, but for **continuous teleop / high-rate command streams** — or any publisher on a lifecycle node — the safe pattern is to **queue in the listener and publish from `tick()`** (which runs on the executor thread): ```python theme={null} def define_interface(self, iface): iface.add_listener(TopicSpec(...), CallbackGroup(self._inbox.append)) def _inbox_append(self, payload): ... # asyncio thread — just enqueue, no rclpy def tick(self): # executor thread — rclpy-safe for cmd in self._drain_inbox(): self.ros_publish(self._cmd_topic, self._build_msg(cmd)) ``` This keeps all rclpy calls on the thread that owns the node and avoids cross-thread access to the publisher cache. *** ## Reference driver: UR Sim (`ursim_driver.py`) Full listing (\~75 lines) in the monorepo. Structure: ```python theme={null} class UrSimDriver(BaseROS2Driver): REGISTRY_ID = "universal_robots/UR7" def define_interface(self, iface): iface.add_publisher( TopicSpec( topic_slug="cyberwave/joint/{twin_uuid}/update", payload_schema_ref="JointStatesPayload", ), CallbackGroup(), from_ros=Ros2TopicSpec(topic="/joint_states"), operation_modes=frozenset(DriverOperationMode), ) def configure(self): ... def connect_to_device(self): ... def activate(self): ... ``` **`main()`** sets logging, `CW_ROS2_AUTO_ACTIVATE`, reads optional manifest/node env, calls **`driver.run()`**. *** ## Lab setup (UR Sim) End-to-end Docker, pendant program, `ur_robot_driver`, and running `ursim_driver.py`: **[UR Sim tutorial](/tutorials/ur-sim-cyberwave-driver)**. Protocol layers (TCP, ROS DDS, MQTT): **[Custom integrations](/overview/connecting-hardware/custom-hardware)**. *** ## `from_ros` vs other patterns | Pattern | Direction | When | | ------------------------------------ | ------------------------------ | --------------------------------------------------------------- | | **`from_ros=Ros2TopicSpec(...)`** | ROS → Cyberwave | Telemetry, joints, poses — **preferred for edge drivers** | | **`CallbackGroup(fn)` + `from_ros`** | ROS → Cyberwave | Transform/filter before MQTT (`convert_joints_to_payload` seam) | | **`add_publisher` + tick callback** | Cyberwave timer → MQTT | Synthetic sensors (no ROS source) | | **`add_listener` + `ros_publish()`** | Cyberwave → ROS | Commands / teleop | | **`JointControllerMixin`** | Cyberwave → ROS (joint teleop) | Registers `joint/update` listener — do not duplicate | | **`twin.joints.set()`** | Cyberwave → MQTT | **Clients only** — application teleop, not driver feedback | | Manual bridge node | Both | Avoid — duplicates registry and alerts | *** ## Troubleshooting | Symptom | Likely cause | | ------------------------------------------- | ------------------------------------------------------------------------------------------------ | | Hangs at *Waiting for ROS lifecycle ACTIVE* | `CW_ROS2_AUTO_ACTIVATE` not `true` and no external activate | | No `ROS forward` log | `define_interface` missing `from_ros`, or wrong `operation_mode` | | Node won't activate / sits inactive | No controller assigned → `NO_OP`; assign a controller (or check `operation_modes`) | | Vendor launch fails or msgs won't import | Read `CW_MANAGED_LAUNCH_LOG`; set `ros_setup`/`ros_overlay` (or `ROS_SETUP`/`ROS_SETUP_OVERLAY`) | | `discovering type for /topic` then error | Topic not published on graph within `discovery_timeout_s` | | MQTT connected but flat joints empty | `JointState.name` / `position` length mismatch — SDK returns `None`, skips publish | | No twin UI alerts | Twin not bound yet, or connect failed before `_enable_backend_alerts` | | `TimeoutError` after 300s | ROS never reached active — check executor spinning and lifecycle | *** ## Related Cyberwave-only lifecycle, registry, manifests, alerts. `cw-driver.yml`, env contract, fake-IMU tutorial. Alert types during connect and failures. # ROS 2 topic namespacing (fleets) Source: https://docs.cyberwave.com/feature-reference/edge/drivers/ros2-topic-namespacing How the UGV driver scopes its ROS 2 nodes and topics per-robot so multiple robots can share one ROS 2 graph without colliding. When several robots of the same model run on one ROS 2 graph, their nodes and topics would collide — every robot otherwise has a `/cmd_vel`, an `/image_raw`, and so on. The UGV driver avoids this by scoping its **entire** ROS 2 graph under a per-robot namespace derived from the twin UUID: ``` ugv_beast_ e.g. ugv_beast_27dca7 ``` So a robot exposes its topics under that namespace: ``` /ugv_beast_27dca7/cmd_vel /ugv_beast_27dca7/image_raw /ugv_beast_27dca7/ugv/led_ctrl ``` The `ugv_beast_` prefix is required because a raw UUID is **not** a valid ROS 2 name (it contains `-` and may start with a digit); the prefix guarantees a valid leading letter. Both the hardware nodes and the MQTT bridge use the same namespace, so topics stay connected. **MQTT topics are unaffected** — they remain keyed by the full twin UUID (`cyberwave/twin/{twin_uuid}/...`). * **Single robot / dev:** with no twin UUID the namespace is empty and topics are global (`/cmd_vel`, `/image_raw`, ...). * **Override:** set `CYBERWAVE_ROS_NAMESPACE` to a valid ROS 2 name to force a specific namespace for both the hardware nodes and the bridge. # Security pipeline (multi-camera, anonymising) Source: https://docs.cyberwave.com/feature-reference/edge/drivers/security-pipeline Two cameras, one worker, zero raw video off the edge. End-to-end privacy-preserving detection pipeline. A two-camera privacy-preserving worker. YOLOv8 detects each person, the worker pixelates their bbox, and the driver substitutes the anonymised frame into the WebRTC stream **before** the bytes leave the edge. ```mermaid theme={null} flowchart LR Cam1[Camera 1] --> Driver1[Driver 1] Cam2[Camera 2] --> Driver2[Driver 2] Driver1 --> Z1[("frames/default
(twin 1)")] Driver2 --> Z2[("frames/default
(twin 2)")] Z1 --> Worker Z2 --> Worker Worker --> P1[("frames/filtered
(twin 1)")] Worker --> P2[("frames/filtered
(twin 2)")] P1 --> Driver1 P2 --> Driver2 Driver1 -->|anonymised| WebRTC[Frontend] Driver2 -->|anonymised| WebRTC Worker -.->|events only| MQTT[Cloud MQTT] ``` ## Why pixelate? Pixelation reads as "a person, doing something" to a human reviewer — unlike stick figures which vanish on occlusion, low light or unusual poses. It also doesn't need a pose model, cutting per-frame CPU cost by roughly 2× on edge devices. See the [Privacy caveat](#privacy-boundary) below — pixelation is visual obscuring, not cryptographic de-identification. ## Pieces | Layer | Component | Notes | | ------------------ | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | Model | `yolov8n` (catalog) | Plain detector; no pose head. Auto-downloaded on first `cw.models.load()`. | | Anonymisation | `cyberwave.vision.anonymize_frame()` | Pixelates each person's bbox. Mode is configurable (`"pixelate"` / `"redact"` / `"blur"` / `"bbox"`). Skeleton overlay disabled. | | Frame substitution | [Frame substitution](./frame-filters) | Driver consults `FILTERED_FRAME_CHANNEL` (`frames/filtered`) before WebRTC encoding when `CYBERWAVE_METADATA_FRAME_FILTER_ENABLED=true` on the twin. | | Routing | `twin_uuid=ctx.twin_uuid` on `cw.data.publish()` | Same worker, two independent streams. See [Multi-Camera Detection Routing](./multi-camera-detection-routing). | ## Worker ```python theme={null} import os import numpy as np from cyberwave.data import FILTERED_FRAME_CHANNEL from cyberwave.vision import anonymize_frame CAMERA_1 = os.environ["CAMERA_1_TWIN"] CAMERA_2 = os.environ["CAMERA_2_TWIN"] model = cw.models.load("yolov8n") def _anonymise(frame, ctx): result = model.predict(frame, classes=["person"], confidence=0.4) # Privacy fail-closed: ``anonymize_frame`` only obscures bbox # regions for matching detections. On a frame where the model # missed everyone (sub-threshold, occluded, partial body) it # would otherwise return the raw frame unchanged and the driver # would substitute that into WebRTC. Publish a black frame # instead — matches the driver's fail-closed behaviour for # stale and shape-mismatched filtered frames. if any(d.label == "person" for d in result.detections): out = anonymize_frame( frame, result.detections, mode="pixelate", draw_skeleton=False, ) else: out = np.zeros_like(frame) cw.data.publish(FILTERED_FRAME_CHANNEL, out, twin_uuid=ctx.twin_uuid) for det in result.detections: if det.area_ratio > 0.3: cw.publish_event(ctx.twin_uuid, "person_too_close", { "area_ratio": round(det.area_ratio, 3), "frame_ts": ctx.timestamp, }) @cw.on_frame(CAMERA_1, sensor="default") def on_camera_1_frame(frame, ctx): _anonymise(frame, ctx) @cw.on_frame(CAMERA_2, sensor="default") def on_camera_2_frame(frame, ctx): _anonymise(frame, ctx) ``` The same gate is applied automatically to workers generated from an [`anonymize`](/feature-reference/workflows/anonymize-image) workflow node, so workflows authored in the visual editor get the same privacy fail-closed behaviour without any code changes. ## Driver configuration Enable the frame filter per camera twin (each generic-camera driver container): ```bash theme={null} CYBERWAVE_METADATA_FRAME_FILTER_ENABLED=true # Optional: widen the freshness window for CPU-only workers # (default 200 ms is tuned for >= 5 Hz GPU workers). CYBERWAVE_METADATA_FRAME_FILTER_FRESHNESS_MS=400 ``` The channel name (`frames/filtered`) and fail-closed blank fallback are hard-coded in the driver. Freshness is tunable per driver via `CYBERWAVE_METADATA_FRAME_FILTER_FRESHNESS_MS` — raise it (e.g. `400`–`500`) for CPU-bound workers, at the cost of keeping visibly-stale anonymised frames on screen longer. `0` is a valid "force blank" fail-close test mode. To see the raw camera feed for debugging, set `CYBERWAVE_METADATA_FRAME_FILTER_ENABLED=false` and restart the driver. When `CYBERWAVE_DETECTION_OVERLAYS` is left at its default (`true`), bounding boxes and labels are drawn **on top** of the anonymised frame and reveal each person's position — which defeats the anonymisation contract for location-sensitive deployments. Set `CYBERWAVE_DETECTION_OVERLAYS=false` alongside the filter flag if that matters. ## Privacy boundary The Zenoh→MQTT bridge does **not** forward `frames/*` channels by default. Only events (`person_too_close`, ...) and detections cross the WAN. The raw and anonymised frames stay on-device. Pixelation is reversible by public depixelation models. It is *deliberate visual obscuring*, not GDPR-grade de-identification. For legal de-identification, combine pixelate with `"redact"` masking or drop frames entirely and publish only events. ## Per-zone alerting with Spatial Filter + Timed Condition For deployments where the pixelation is just the privacy scaffold and the *actual* alert is "person loitering inside a restricted polygon", combine this driver setup with a workflow that wires [`spatial_filter`](/feature-reference/workflows/spatial-filter) and [`timed_condition`](/feature-reference/workflows/timed-condition) downstream of `call_model` + `anonymize`. The polygon also renders as a read-only overlay on the twin's WebRTC stream so operators can see which zones are armed without opening every workflow. See the [Zone-based intrusion detection tutorial](/tutorials/intrusion-detection) for the full end-to-end recipe. ## Reference implementation * Worker: [`cyberwave-sdks/cyberwave-python/examples/security_pipeline/`](https://github.com/cyberwave-os/cyberwave-python/tree/main/examples/security_pipeline) * End-to-end test: `cyberwave-edge-nodes/test_security_pipeline.sh` # Writing compatible drivers Source: https://docs.cyberwave.com/feature-reference/edge/drivers/writing-compatible-drivers Build a platform-compliant edge driver for your own asset: container contract, cw-driver.yml interface manifest, MQTT catalog, and sensor output. ## What is a compatible driver? A compatible driver connects **your hardware's native API** to a **Cyberwave asset and twin**: it translates the device's protocol into MQTT topics, command envelopes, and (optionally) edge data channels that the UI, workflows, and SDK understand. This guide is for **integrators building a driver from scratch** for a custom or third-party asset in your workspace. Cyberwave-maintained drivers use the same rules; their `cw-driver.yml` files are linked later as examples only. Drivers can run on edge hardware, on the robot, in the cloud, or on a developer laptop. In production they usually run beside the device under **Edge Core**. Each driver ships as a **Docker image**. Edge Core pulls and runs it with the environment variables below, so local development matches production deployment. *** ## Choose a starting path End-to-end Docker lab + `ursim_driver.py`. SDK concepts: [Python SDK drivers](#python-sdk-drivers) below. Synthetic IMU on a D455 twin — manifest, commands, MQTT + optional Zenoh before real sensors. **BaseDriver** from scratch — serial, SDK, WebRTC, or hand-written MQTT. Deep references: **[BaseDriver](/feature-reference/edge/drivers/base-driver-class)** · **[BaseROS2Driver](/feature-reference/edge/drivers/ros2-base-driver)** *** ## Quickstart: Python SDK Use the **[`cyberwave`](https://pypi.org/project/cyberwave/)** package and **`BaseDriver`** in `cyberwave.driver`. You declare topics and commands in Python; the SDK generates the MQTT catalog and wires runtime subscriptions. Lifecycle, hooks, manifest export, alerts, and what the SDK runs for you. Dual lifecycle, `from_ros` forwarding, hooks — often under 100 LOC for ROS → twin streaming. ```python theme={null} from cyberwave import Cyberwave from my_driver import MyDriver cw = Cyberwave() twin = cw.twin("acme-corp/my-device", twin_id="...") # 1. Register catalog on the twin (no running driver required) twin.driver.set_schema(MyDriver.get_manifest()) # 2. Optional: export cw-driver.yml for Docker / git MyDriver.get_manifest(path="cw-driver.yml") # 3. Run — driver wires MQTT (+ Zenoh when declared) MyDriver(twin=twin).run() # Introspection vs invocation print(twin.commands.get_supported_commands()) # command catalog introspection twin.commands.get_schema() # MQTT catalog (topics, commands.specs) twin.commands.stop() # bound methods from commands.supported ``` `get_manifest()` builds the compiled **MQTT** catalog from `define_interface()` only — no twin connect, no `run()`. Use `get_manifest_bundles()` when you also declare Zenoh channels (see [Zenoh data bus](#option-a-zenoh-data-bus-recommended)). | Handle | Role | | --------------- | ----------------------------------------------------------------------------------------------------------------- | | `twin.driver` | Full catalogs (`get_schemas`, Zenoh/topics/transports getters) and **`set_schema`** (persist + re-bind commands) | | `twin.commands` | **`get_schema()`**, **`get_supported_commands()`**, and **`twin.commands.(...)`** from `commands.supported` | **ROS 2 integrators:** start with the **[UR Sim tutorial](/tutorials/ur-sim-cyberwave-driver)**, then read [Python SDK drivers](#python-sdk-drivers) below for what the SDK handles vs what you implement. Otherwise see the [fake IMU tutorial](#tutorial-build-your-first-driver-fake-imu), then [the `cw-driver.yml` reference](#declare-your-driver-interface-cw-driveryml) for `cw-driver.yml`, REST/MQTT, and sensor buses. (C++ drivers use the same platform contract via `cw-driver.yml`; see the [C++ SDK](/overview/tools/cpp-sdk).) *** ## Python SDK drivers The [`cyberwave`](https://pypi.org/project/cyberwave/) package provides **base classes** so you declare the platform contract once in Python instead of hand-wiring MQTT and catalog JSON. | Base class | Use when | | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | | **[`BaseDriver`](/feature-reference/edge/drivers/base-driver-class)** | Serial, vendor SDK, WebRTC, cameras, custom polling loops | | **[`BaseROS2Driver`](/feature-reference/edge/drivers/ros2-base-driver)** | ROS 2 Humble+ — subscribe on ROS topics and forward to Cyberwave with **`from_ros=`** | ### What you declare vs what the SDK runs | You provide | SDK provides automatically | | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | **`REGISTRY_ID`** on the driver subclass (required) | `Cyberwave(source_type="edge")` — API/MQTT from env / CLI | | **`define_interface(iface)`** — topics, commands, `from_ros` | Compiles `metadata["mqtt"]` / optional `metadata["zenoh"]`; `twin.driver.set_schema` | | Lifecycle hooks (`on_*` or ROS `configure` / `activate`) | MQTT subscribe/publish wiring, tick publishers, session telemetry | | Optional publisher/command callbacks | Default management commands (`stop`, teleop modes), `driver_info` on `twin/telemetry` | | Optional `operation_modes=` per interface entry | **Operation mode derived from the twin's attached controller** at startup (`NO_OP` when none) and re-wired on controller/teleop commands | | — | Lifecycle **twin alerts** (*Driver starting* → *Driver active*) after connect | | **`from_ros=Ros2TopicSpec(...)`** only on ROS drivers | ROS subscribe + `JointState` → `cyberwave/joint/{uuid}/update` serialization | **Source-type convention.** A driver **publishes** its state as **`edge`** (or **`sim`** when driving a simulator) and **listens** for teleop commands — **`tele`**, `edit`, `sim_tele`. It must **never act on `edge*`** messages (that's its own feedback), and inbound messages with **no** `source_type` are accepted leniently. Full rules: [BaseDriver → Source-type convention](/feature-reference/edge/drivers/base-driver-class#source-type-convention). A driver with **no controller assigned starts in `NO_OP`** — control commands stay idle while edge telemetry/`from_ros` forwarders keep streaming. Declare always-on publishers with `operation_modes=frozenset(DriverOperationMode)`. See [Operation modes](/feature-reference/edge/drivers/base-driver-class#operation-modes-driveroperationmode). High-rate streams should throttle with `TopicSpec.rate_hz` on `from_ros` publishers (or `acquire_stream_publish_slot()` in custom callbacks; default cap 30 Hz). ROS drivers can also have the SDK spawn a vendor `ros2 launch` (`managed_launch`) and export a combined ROS+MQTT `manifest.yaml` (`write-manifest`) — see the [BaseROS2Driver reference](/feature-reference/edge/drivers/ros2-base-driver#managed-vendor-launch-managed_launch). ### Driver mixins (arm + joints) For manipulator arms, compose SDK mixins instead of hand-wiring MQTT joint teleop, arm commands, and ROS feedback. See **[Driver mixins and capabilities](/feature-reference/edge/drivers/driver-mixins)** for the full inventory and a **Piper walkthrough**. | Concern | Mixin / pattern | | --------------------------------------- | --------------------------------------------------------------------------------------- | | MQTT `joint/update` teleop in | `JointControllerMixin` (`use_joint_controller=True`) — **do not** add your own listener | | `ee_move`, `grip`, `home`, … | `ArmCapabilityMixin` (`use_base_commands=True`) | | ROS → local joint state + MQTT feedback | `Ros2JointFeedbackMixin` + `add_publisher(..., from_ros=...)` in `define_interface` | | Async MQTT → ROS executor hand-off | `JointCommandBufferMixin` — `_publish_joint_command`, `tick()` | **Bidirectional `joint/update`:** call `super().define_interface(iface)` first (mixins register the **teleop listener**); then add your **edge publisher** with `from_ros`. Clients use `twin.joints.set()` for commands and `twin.joints.get()` to read feedback — drivers use the registry, not `twin.joints.set()`. #### Integration example: `PiperDriver` Reference: [`cyberwave-edge-nodes/piper/piper_driver.py`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-edge-nodes/piper/piper_driver.py). ```python theme={null} class PiperDriver( JointControllerMixin, ArmCapabilityMixin, Ros2JointFeedbackMixin, JointCommandBufferMixin, BaseROS2Driver, ): use_joint_controller = True use_joint_feedback = True use_base_commands = True def __init__(self, node_name, **kwargs): super().__init__(node_name, **kwargs) self._init_joint_feedback() self._init_joint_command_buffer() def define_interface(self, iface): super().define_interface(iface) # listeners: joint/update + twin/command iface.add_publisher( # publisher: joint/update @ edge only TopicSpec(namespace="joint", leaf="update", rate_hz=30.0, ...), CallbackGroup(), protocol=ProtocolArgs(source_types=[SOURCE_TYPE_EDGE]), from_ros=Ros2TopicSpec(topic="joint_states_single"), ) def joint_controller_motion(self): return None # passthrough — Piper sets vel/effort on the ROS JointState def joint_controller_after_process(self): return lambda cmd: self.submit_joint_targets(cmd.positions) def tick(self): self.pump_joint_commands() # inbox → _publish_joint_command → ros_publish ``` | Step | Responsibility | | ----------------- | ------------------------------------------------------- | | MQTT teleop in | `JointControllerMixin` → `submit_joint_targets` | | Arm commands | `ArmCapabilityMixin` → IK → same controller path | | ROS cmd out | `JointCommandBufferMixin._publish_joint_command` | | ROS feedback in | `Ros2JointFeedbackMixin` updates `_joint_states` for IK | | MQTT feedback out | `from_ros` forwarder (30 Hz, `source_type=edge`) | Motion shaping (trapezoidal vs passthrough): [Joint motion shaping](/feature-reference/edge/drivers/joint-motion-shaping). MRO, seams, Piper-style ROS arm pattern. `joint_controller_motion()` — shaped vs passthrough. ### ROS 2 minimal example (`ursim_driver.py`) Flagship sample: [`examples/ursim_driver.py`](https://github.com/cyberwave-os/cyberwave/blob/main/cyberwave-sdks/cyberwave-python/examples/ursim_driver.py) (\~75 lines). ```python theme={null} from cyberwave.driver import CallbackGroup, TopicSpec from cyberwave.driver.ros2 import BaseROS2Driver, Ros2TopicSpec class UrSimDriver(BaseROS2Driver): REGISTRY_ID = "universal_robots/UR7" def define_interface(self, iface): iface.add_publisher( TopicSpec( topic_slug="cyberwave/joint/{twin_uuid}/update", payload_schema_ref="JointStatesPayload", ), CallbackGroup(), # JointState auto-serialized — no manual MQTT loop from_ros=Ros2TopicSpec(topic="/joint_states"), ) ``` Run after ROS and UR Sim are up (full lab): **[UR Sim tutorial](/tutorials/ur-sim-cyberwave-driver)**. Docker, pendant program, `ur_robot_driver`, run `ursim_driver.py`, GIFs. TCP, ROS DDS, MQTT — how the lab stack fits together. Dual lifecycle, env vars, `ros_publish()` for commands. Non-ROS drivers, manifest export, hooks. Arm + joint mixin composition, bidirectional joint/update. *** ## Tutorial: build your first driver (fake IMU) Reference implementation: **`cyberwave-python/examples/fake_imu_driver.py`** — hardware-free, useful to validate manifest + MQTT + `twin.imu.get()` before real sensors. **ROS 2 arms:** use the **[UR Sim tutorial](/tutorials/ur-sim-cyberwave-driver)** and [Python SDK drivers](#python-sdk-drivers). ```bash theme={null} export CYBERWAVE_API_KEY=... export CYBERWAVE_TWIN_UUID= # optional cd cyberwave-python PYTHONPATH=. python examples/fake_imu_driver.py ``` ### Step 1 — Class skeleton and identity ```python theme={null} class FakeImu6dDriver(BaseDriver): REGISTRY_ID = "intel/realsensed455" TICK_RATE_HZ = 50.0 auto_register_interface = False # demo calls set_schema() before run() ``` `REGISTRY_ID` ties the driver to a catalog asset. `TICK_RATE_HZ` drives both `on_tick` and registry publisher scheduling. ### Step 2 — `define_interface` (manifest + runtime contract) ```python theme={null} def define_interface(self, iface): iface.add_listener( TopicSpec(namespace="twin", leaf="command", payload_schema_ref="TwinCommandPayload"), CallbackGroup(callback=self._on_rotate), command=CommandArgs(name="rotate"), protocol=ProtocolArgs(source_types=[SOURCE_TYPE_TELE]), ) iface.add_publisher( TopicSpec( topic_slug=TWIN_IMU_TOPIC_SLUG, payload_schema_ref="ImuPayload", enable_zenoh=True, zenoh_channel="imu", ), CallbackGroup(callback=self._publish_imu_sample), publisher=PublisherArgs(rate_hz=self._imu_params.imu_rate_hz), protocol=ProtocolArgs(source_types=[SOURCE_TYPE_EDGE]), ) ``` A driver publishes state as `edge` and listens for commands as `tele`, so the two declarations never share a value. Import them from `cyberwave.constants` rather than spelling them inline — a string outside the enum is accepted here and silently coerced downstream. This single method feeds `get_manifest()` / `driver.manifest`, optional **`metadata["zenoh"]`**, and `_wire_interface_from_registry()` (MQTT subscribe/publish plus edge **DataBus** when dual specs are present). **`twin/command` stays MQTT-only** — do not set `enable_zenoh=True` on command listeners. ### Step 3 — Lifecycle hooks (map to `run_async` order) | Hook | Fake IMU behavior | | ----------------------- | ---------------------------------------- | | `on_configure` | Log params (`sensor_id`, rate) | | `on_connect_to_device` | No hardware — log ready | | `on_register_callbacks` | `pass` — no device SDK callbacks | | `on_activate` | Log IMU topic active; `emit_driver_info` | | `on_shutdown` | `pass` | For a real camera driver, `on_connect_to_device` opens the device SDK and `on_register_callbacks` attaches frame callbacks. ### Step 4 — Publisher callback (MQTT stream) ```python theme={null} def _publish_imu_sample(self) -> ImuPayload: gyro, accel = random_imu_vectors(gyro_base=self._imu.gyro(), ...) return build_imu_payload(gyro=gyro, accel=accel, sensor_id=self._imu_params.sensor_id) ``` `BaseDriver` calls this from `_run_registry_publishers()` at 50 Hz and publishes to `cyberwave/twin/{uuid}/imu`. You do **not** call `mqtt.publish` yourself for registry publishers. ### Step 5 — Command callback (`rotate`) ```python theme={null} def _on_rotate(self, envelope: dict[str, Any]) -> None: if envelope.get("command") == "status": return data = envelope.get("data") or {} axis = str(data.get("axis", "")).lower() rate_deg_s = float(data.get("amount_deg", 0.0)) logger.info("command received, rotating sensor ...") self._imu.set_gyro_rate_deg_s(axis, rate_deg_s) ``` `twin.commands.rotate(...)` publishes to `cyberwave/twin/{uuid}/command`; the registry routes it here while the driver is **ACTIVE**. ### Step 6 — Twin bring-up script (recommended order) | Order | Action | | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | Create / resolve twin; add `d455_imu` to `capabilities.sensors` if missing (D455 has no hardware IMU) | | 2 | `twin.driver.set_schema(FakeImu6dDriver.get_manifest())` — persists `metadata["mqtt"]` / `metadata["zenoh"]` and **re-binds** `twin.commands.*` | | 3 | `driver.run()` or `asyncio.create_task(driver.run_async())` on the **main** thread | | 4 | `twin.imu.get(timeout=5)` from a consumer client while ACTIVE | | 5 | `twin.commands.rotate(axis="yaw", amount_deg=30, source_type="tele")` | **Expected logs:** `inactive → active`, `IMU stream active`, then `command received, rotating sensor` on the driver logger; `imu.get()` shows higher `gyro.z` after yaw rotate (\~0.52 rad/s + noise). `rotate` is a **sensor command** (not locomotion) — no teleop policy required on camera-only twins. ### Minimal skeleton (any driver) ```python theme={null} from cyberwave.driver import BaseDriver, CallbackGroup, CommandArgs, TopicSpec class MyDriver(BaseDriver): REGISTRY_ID = "acme-corp/my-arm-v1" def define_interface(self, iface): iface.add_listener( TopicSpec(namespace="twin", leaf="command", payload_schema_ref="TwinCommandPayload"), CallbackGroup(callback=self._on_stop), command=CommandArgs(name="stop"), ) async def on_configure(self): ... async def on_connect_to_device(self): ... async def on_register_callbacks(self): ... async def on_activate(self): ... async def on_shutdown(self): ... @classmethod def create(cls): return cls.from_env() ``` ### Registry API reference | API | Role | | ------------------------------------- | ------------------------------------------------------------------------------- | | `define_interface(iface)` | **Source of truth** — topics, commands, callbacks | | `CustomDriver.get_manifest()` | Classmethod → compiled **MQTT** bundle for `twin.driver.set_schema` | | `CustomDriver.get_manifest_bundles()` | `{ "mqtt": ..., "zenoh": ... \| null }` — both catalogs from `define_interface` | | `CustomDriver.get_manifest(path=...)` | Also write `cw-driver.yml` | | `driver.manifest` | Compiled MQTT bundle on a live instance | | `driver.register_interface_on_twin()` | `twin.driver.set_schema(manifest)` on bound twin | | `DriverOperationMode` | Gates actuation-related listeners | | `BaseTelemetry` | Debounced `driver_info` on `twin/telemetry` | Session markers (`telemetry_start`, `connected`, …) use `client.mqtt` directly. Queue operational fields with `emit_driver_info()`; the registry telemetry publisher flushes them. *** ## Twin SDK: `twin.driver` vs `twin.commands` After you register a catalog with **`twin.driver.set_schema(...)`**: The fastest way to get started is the **Cyberwave Driver skill** for [Claude Code](https://claude.ai/claude-code). It asks you a few questions about your hardware and scaffolds a complete, production-ready driver project — including the Dockerfile, local dev setup, and a working twin connection. **Install the skill:** ```bash theme={null} git clone https://github.com/cyberwave-os/driver-skill ~/.claude/skills/cyberwave-driver ``` Then in any Claude Code session: ``` /cyberwave-driver ``` Claude will generate the full project tree and walk you through connecting it to a real twin locally. The skill source is open source at [cyberwave-os/driver-skill](https://github.com/cyberwave-os/driver-skill). *** ## Quickstart: use the SDK The fastest way to write a compatible driver is to use one of the official SDKs: * **Python SDK** — [`cyberwave-sdk`](https://pypi.org/project/cyberwave/) * **C++ SDK** — see the [C++ SDK docs](/overview/tools/cpp-sdk) The SDKs handle twin synchronization, file I/O, reconnection logic, and more, so you can focus on the hardware integration. ## Environment variables When Edge Core starts a driver container it injects the following environment variables. You can develop your driver assuming these are always set to valid values — no need to handle the case where they are absent. | Variable | Description | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `CYBERWAVE_TWIN_UUID` | UUID of the twin instance this driver manages | | `CYBERWAVE_API_KEY` | API key scoped to this driver for authenticating platform calls | | `CYBERWAVE_TWIN_JSON_FILE` | Absolute path to a writable JSON file containing the twin's current state (see [Twin JSON file](#twin-json-file)) | | `CYBERWAVE_CHILD_TWIN_UUIDS` | *(optional)* Comma-separated UUIDs of child twins (e.g. cameras) attached to this driver | `CYBERWAVE_CHILD_TWIN_UUIDS` is set when child twins are attached to the driver twin. Drivers can use this to coordinate child devices (for example, multiple cameras) without additional configuration. ### Restart behavior tuning The following optional variables let you override Edge Core's restart defaults: | Variable | Default | Description | | ---------------------------------------------- | ---------------------------- | ---------------------------------------------------------- | | `CYBERWAVE_DRIVER_RESTART_LOOP_THRESHOLD` | `4` | Number of restarts before the driver is marked as flapping | | `CYBERWAVE_DRIVER_RESTART_LOOP_WINDOW_SECONDS` | `60` | Time window (seconds) used to count restarts | | `CYBERWAVE_DRIVER_TROUBLESHOOTING_URL` | `https://docs.cyberwave.com` | URL surfaced in platform alerts for operator guidance | ## Driver failure handling Drivers must exit with a **non-zero** code when they cannot access required hardware (for example, a missing `/dev/video*` device or a disconnected peripheral). This allows Edge Core to detect startup failures and trigger restart logic. Edge Core raises the following alerts: * `driver_start_failure` — raised when a driver container cannot reach a stable running state. * `driver_restart_loop` — raised when a driver exceeds the restart threshold within the window. The container is stopped and marked as flapping. ## Twin JSON file `CYBERWAVE_TWIN_JSON_FILE` points to a JSON file on disk that contains the digital twin instance (including its `metadata`) and the associated catalog twin data, matching the `TwinSchema` and `AssetSchema` API schemas. Drivers may read and modify this file. Edge Core syncs any changes back to the backend when connectivity is available. ## Runtime configuration Drivers should treat `metadata["edge_configs"]` as the source of truth for per-device runtime configuration, and `metadata["edge_fingerprint"]` as the edge identity (not duplicated inside `edge_configs`). Read `edge_configs` from `CYBERWAVE_TWIN_JSON_FILE` at startup to obtain per-device settings without hardcoding them in the image. ## Declare your driver interface (`cw-driver.yml`) To make a **custom asset** work with Cyberwave, your driver project should include a **`cw-driver.yml`** at the repository root (next to your `Dockerfile`). The file is the **contract** between your hardware bridge, the platform APIs, the web UI, and the SDK: it lists which MQTT topics you use and which command strings you accept. Cyberwave’s own edge drivers (Go2, SO-101, DJI Mini, and others) use the same format — treat them as **reference implementations**, not as something you must fork. Copy the patterns that match your robot (locomotion, joint bus, camera stream, etc.) and trim what you do not implement. ### Compliance checklist | Step | What you do | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1. **Asset** | Create an asset in your workspace for the hardware type you are integrating. Note its `registry_id` (or `slug`) — your manifest must target that id. | | 2. **Manifest** | Add `cw-driver.yml` to your driver repo. Declare every topic segment and `commands.supported` entry your code actually handles. | | 3. **Implement** | Subscribe/publish on the MQTT topics from your catalog (e.g. `cyberwave/twin/{uuid}/command`); see [Runtime messaging (MQTT)](#runtime-messaging-mqtt) and [MQTT API Reference](/api-reference/mqtt/main). | | 4. **Register interface** | `twin.driver.set_schema("./cw-driver.yml")` → `POST /api/v1/twins/{uuid}/driver-schema` (see [Apply the manifest](#apply-the-manifest-to-your-twin) and [Platform API reference](#platform-api-reference)). | | 5. **Deploy** | Run the image with Edge Core (or locally with the same env vars). New twins spawned from that asset inherit `metadata["mqtt"]`. | If the manifest and the running driver disagree (undeclared command, wrong topic), teleop, agents, and SDK helpers will not line up with what the hardware actually does. ### Why you need it Without a declared interface catalog, the platform cannot know which MQTT topics your driver uses, which command strings are valid on `cyberwave/twin/{uuid}/command`, or whether a command is **continuous** (stick-held) vs **discrete** (one-shot). That metadata drives: | Consumer | What it uses from the catalog | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | **Web UI** | Dynamic control surfaces — e.g. the keyboard teleop overlay lists only `commands.supported` entries and respects `commands.specs[name].continuous` | | **Python SDK** | `twin.commands.get_schema()` and catalog methods such as `twin.commands.move_forward(...)` bound from `commands.supported` | | **Your driver** | A single source of truth for reviews, tests, and parity with production behavior | **Planned** — topic entries will also reference dedicated payload schemas (protobuf / robot-native layouts) for typed robot data on the wire. Today, `payload_schema_ref` names the logical schema; strict validation against those refs is not enforced yet. ### What `cw-driver.yml` contains Top-level fields: | Field | Purpose | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `registry_ids` | One or more asset `registry_id` values this manifest describes — use the id of **your** workspace asset (e.g. `acme-corp/my-arm-v1`) | | `mqtt.schema_version` | Catalog format version (currently `1`) | | `mqtt.driver_family` | Implementation hint (`ros_cpp`, `python`, `android`, …) | | `mqtt..` | Per-topic contract — see [YAML path → MQTT topic](#yaml-path--mqtt-topic) below | | `mqtt.commands.supported` | Command names the driver accepts on the twin command topic — plain strings (discrete) or `{name, continuous, rate_hz, description}` objects | | `mqtt.commands.routers` | Optional routing hints for the edge bridge (e.g. `actuation`, `get_status`) | | `mqtt.commands.constraints` | Human-readable rules (source types, safety notes) surfaced to agents and docs | ### YAML path → MQTT topic Topic entries are nested as **`mqtt..`**. The leaf key is the **MQTT path segment** (use hyphens in YAML, e.g. `webrtc-offer`). Each entry becomes a flat key in `metadata["mqtt"]["topics"]` by joining a namespace prefix with the leaf: | YAML path | Compiled slug | Example live topic (`twin_uuid = abc`) | | ---------------------------- | ------------------------------------------------- | -------------------------------------- | | `mqtt.joint.update` | `cyberwave/joint/{twin_uuid}/update` | `cyberwave/joint/abc/update` | | `mqtt.joint.+` | `cyberwave/joint/{twin_uuid}/+` | `cyberwave/joint/abc/+` (wildcard) | | `mqtt.twin.command` | `cyberwave/twin/{twin_uuid}/command` | `cyberwave/twin/abc/command` | | `mqtt.twin.position` | `cyberwave/twin/{twin_uuid}/position` | `cyberwave/twin/abc/position` | | `mqtt.twin.telemetry` | `cyberwave/twin/{twin_uuid}/telemetry` | `cyberwave/twin/abc/telemetry` | | `mqtt.twin.webrtc-offer` | `cyberwave/twin/{twin_uuid}/webrtc-offer` | `cyberwave/twin/abc/webrtc-offer` | | `mqtt.twin.webrtc-answer` | `cyberwave/twin/{twin_uuid}/webrtc-answer` | `cyberwave/twin/abc/webrtc-answer` | | `mqtt.twin.webrtc-candidate` | `cyberwave/twin/{twin_uuid}/webrtc-candidate` | `cyberwave/twin/abc/webrtc-candidate` | | `mqtt.environment.` | `cyberwave/environment/{environment_uuid}/` | environment-scoped | **Namespace prefixes:** | `mqtt` namespace | MQTT prefix | | ---------------- | ------------------------------------------ | | `joint` | `cyberwave/joint/{twin_uuid}` | | `twin` | `cyberwave/twin/{twin_uuid}` | | `environment` | `cyberwave/environment/{environment_uuid}` | Each leaf entry sets `direction`, `payload_schema_ref`, `description`, and optional `source_types`. **WebRTC** signaling is always on the **twin** prefix (`cyberwave/twin/{uuid}/webrtc-offer`, `webrtc-answer`, `webrtc-candidate`, and `webrtc-command` for media-service commands). Declare them under **`mqtt.twin`** with hyphenated leaf names — not as a separate top-level namespace: ```yaml theme={null} mqtt: twin: command: # ... webrtc-offer: direction: both payload_schema_ref: WebRTCOfferPayload webrtc-answer: direction: both payload_schema_ref: WebRTCAnswerPayload ``` Only list WebRTC leaves when **this twin** participates in signaling (e.g. onboard camera or gimbal stream). Arm-only or joint-bus drivers (such as SO-101) should omit them; camera video uses **child camera twins** and the media service, not WebRTC topics on the arm twin. In some first-party Cyberwave profiles you may see a legacy `mqtt.webrtc.offer` shorthand (`offer` → `webrtc-offer` under the twin prefix). For **new** drivers, use `mqtt.twin.webrtc-*` only. ### Compiled catalog shape On the platform, your asset (and twins created from it) store a JSON bundle at **`metadata["mqtt"]`**: * `topics` — map of canonical slug → `{ direction, payload_schema_ref, description, … }` * `commands.supported` — list of command name strings * `commands.specs` — per-command flags such as `continuous`, `rate_hz`, and `description` (defaults to `""`) * `schema_version`, `driver_family` — format and implementation hints expand with a worked example once the description field has shipped on more than one driver family. **`metadata["zenoh"]`** (optional, edge workers on the same host): * `channels` — map of channel name → `{ direction, payload_schema_ref, description, … }` * `locality` — typically `edge_colocated` * `schema_version`, `driver_family` — same versioning pattern as MQTT Author in YAML (or Python `define_interface`); the SDK compiles into metadata when you call **`twin.driver.set_schema`**. That call also **re-binds** `twin.commands.` from the updated `commands.supported` list. ### Reference implementations (Cyberwave drivers) Use these open-source manifests as templates — copy the namespaces and command style that match your hardware, then delete what you do not implement: | Profile | Manifest | Good template for | | ---------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | UGV Beast | [cw-driver.yml](https://github.com/cyberwave-os/cyberwave-edge-ros-ugv/blob/main/cw-driver.yml) | Mobile base, continuous locomotion, discrete utilities | | SO-101 arm | [cw-driver.yml](https://github.com/cyberwave-os/cyberwave-edge-so101/blob/main/cw-driver.yml) | `joint` bus + `twin.command` script commands (no WebRTC on the arm twin) | ### Apply the manifest to your twin After you author `cw-driver.yml`, register it on a **twin you own** with the Python SDK. You do not need to hand-build JSON or call low-level asset APIs — point `set_schema` at your manifest file and the platform updates that twin's `metadata["mqtt"]`, refreshes the catalog cache, and binds **catalog-derived command methods** on `twin.commands` (for example `twin.commands.stop()`, `twin.commands.move_forward(...)` when those names appear in `commands.supported`). ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="...") twin = cw.twin(twin_id="your-twin-uuid") # or resolve from environment # Compile cw-driver.yml, persist on this twin, re-bind catalog methods twin.driver.set_schema("./cw-driver.yml") # Inspect the catalog the UI and SDK now use print(twin.commands.get_schema()["commands"]["supported"]) # Call any command you declared — derived from the manifest twin.commands.stop() twin.commands.move_forward(linear_x=0.3, duration=0.5, rate_hz=10) ``` Set `registry_ids` in the YAML to match the asset your twin was created from. Re-run `set_schema` whenever you change the manifest so teleop, agents, and SDK callers stay aligned with your driver. #### `set_schema` — REST and SDK | | | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Python SDK** | `twin.driver.set_schema(path_or_dict, merge=True)` — compiles `cw-driver.yml`, calls the driver-schema API, re-binds `twin.commands.` | | **REST** | `POST /api/v1/twins/{uuid}/driver-schema` | | **Auth** | `Authorization: Bearer ` (same as `CYBERWAVE_API_KEY`) | | **Request body** | `{ "metadata": { "mqtt": { "schema_version": 1, "topics": { ... }, "commands": { "supported": [...], "specs": { ... } }, ... } } }` — only fields you want to change need to be sent; `set_schema` sends the full `metadata` object with `mqtt` set or merged | | **Response** | `TwinSchema` including updated `metadata` | | **Read back** | `GET /api/v1/twins/{uuid}` → `metadata.mqtt`; SDK: `twin.commands.get_schema()` | Full OpenAPI entry: [Update Twin](/api-reference/rest/DefaultApi#src_app_api_twins_update_twin). `merge=True` (default) deep-merges the new `metadata.mqtt` into existing twin metadata. `merge=False` replaces the entire `mqtt` block. Invoke catalog commands after `set_schema` — they publish over **MQTT**, not REST: | SDK | Wire | | ----------------------------------- | --------------------------------------------------------------------------------------------------------- | | `twin.commands.(**kwargs)` | Publish to `cyberwave/twin/{twin_uuid}/command` with envelope `{ source_type, command, data, timestamp }` | ### Platform API reference Use the **Python SDK** for day-to-day driver work; use **REST** when integrating from another language or CI. All REST paths are under `/api/v1` and require a bearer token unless noted otherwise. See the [REST API reference](/api-reference/rest/DefaultApi) for request/response schemas. #### Bring-up (workspace) | Step | REST | Python SDK | | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | Create catalog asset | `POST /api/v1/assets` — [Create Asset](/api-reference/rest/DefaultApi#src_app_api_assets_create_asset) | `client.assets.create(...)` | | Check `registry_id` free | `GET /api/v1/assets/check-registry-id/{registry_id}` — [Check Registry Id](/api-reference/rest/DefaultApi#src_app_api_assets_check_registry_id_availability) | — | | Update asset (optional shared catalog on asset) | `PUT /api/v1/assets/{uuid}` — [Update Asset](/api-reference/rest/DefaultApi#src_app_api_assets_update_asset) — set `metadata.mqtt` on the asset if every new twin should inherit the same manifest | `client.assets.update(asset_uuid, {"metadata": {"mqtt": ...}})` | | Create twin | `POST /api/v1/twins` — [Create Twin](/api-reference/rest/DefaultApi#src_app_api_twins_create_twin) | `client.twins.create(...)` | | List twins in environment | `GET /api/v1/environments/{uuid}/twins` — [Get Environment Twins](/api-reference/rest/DefaultApi#src_app_api_environments_get_environment_twins) | environment helpers / twin resolution | | Register driver manifest on **one twin** | `POST /api/v1/twins/{uuid}/driver-schema` | `twin.driver.set_schema("./cw-driver.yml")` | | Read twin + catalog | `GET /api/v1/twins/{uuid}` — [Get Twin](/api-reference/rest/DefaultApi#src_app_api_twins_get_twin) | `twin.commands.get_schema()` or `twin.refresh()` | #### Runtime state (REST alternatives to MQTT) Drivers normally stream state over **MQTT** (see below). These REST endpoints are available for tools, simulators, or HTTP-only bridges: | Data | REST | Python SDK | | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | | Pose (position / rotation / scale) | `PATCH /api/v1/twins/{uuid}/state` — [Update Twin State](/api-reference/rest/DefaultApi#src_app_api_twins_update_twin_state) | `client.twins.update_state(twin_uuid, {...})` | | Joint states (HTTP) | `PUT /api/v1/twins/{uuid}/joint_states` — [Update Twin Joint States](/api-reference/rest/DefaultApi#src_app_api_urdf_update_twin_joint_states) | `client.twins.update_joint_state(...)` / URDF helpers | | Single joint | `PUT /api/v1/twins/{uuid}/joints/{joint_name}/state` — [Update Twin Joint State](/api-reference/rest/DefaultApi#src_app_api_urdf_update_twin_joint_state) | — | | Latest camera frame | `GET /api/v1/twins/{uuid}/latest-frame` — [Get Twin Latest Frame](/api-reference/rest/DefaultApi#src_app_api_twins_get_twin_latest_frame) | `client.twins.get_latest_frame(...)` | | Driver logs | `GET /api/v1/twins/{uuid}/logs` — [Get Twin Driver Logs](/api-reference/rest/DefaultApi#src_app_api_twins_get_twin_driver_logs) | — | #### Runtime messaging (MQTT) Declared in `cw-driver.yml` → compiled into `metadata.mqtt.topics`. At runtime the driver (or SDK teleop) uses the **MQTT broker** (WebSocket URL in `NEXT_PUBLIC_MQTT_URL` for frontends; port `1883` / `9001` locally for edge). Topic prefix may include an environment segment in deployed stacks; slugs below are canonical. | Catalog slug (`metadata.mqtt.topics` key) | Example topic | Typical driver role | | --------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------- | | `cyberwave/twin/{twin_uuid}/command` | `cyberwave/twin/abc/command` | **Subscribe** for `source_type: tele` commands; map `command` string to hardware | | `cyberwave/joint/{twin_uuid}/update` | `cyberwave/joint/abc/update` | **Subscribe** for tele joint targets; **publish** follower/sim observations | | `cyberwave/twin/{twin_uuid}/position` | `cyberwave/twin/abc/position` | **Publish** pose updates | | `cyberwave/twin/{twin_uuid}/telemetry` | `cyberwave/twin/abc/telemetry` | **Publish** lifecycle / status JSON | | `cyberwave/twin/{twin_uuid}/webrtc-offer` | `cyberwave/twin/abc/webrtc-offer` | **Subscribe/publish** signaling (camera twins) | | `cyberwave/twin/{twin_uuid}/webrtc-answer` | `cyberwave/twin/abc/webrtc-answer` | Signaling | | `cyberwave/twin/{twin_uuid}/webrtc-candidate` | `cyberwave/twin/abc/webrtc-candidate` | ICE candidates | | SDK publish helper | MQTT topic pattern | Typical caller | | --------------------------------------- | -------------------------------- | ------------------------------------------- | | `twin.commands.(...)` | `cyberwave/twin/{uuid}/command` | SDK clients, UI | | `twin.joints.set(...)` | `cyberwave/joint/{uuid}/update` | **Application teleop** (commands) | | `define_interface` + `from_ros` | `cyberwave/joint/{uuid}/update` | **Edge drivers** (measured `edge` feedback) | | `client.mqtt.update_joints_state(...)` | `cyberwave/joint/{uuid}/update` | Scripts, sims, non-registry publishers | | `client.mqtt.update_twin_position(...)` | `cyberwave/twin/{uuid}/position` | Drivers, sims | | `client.mqtt.update_twin_rotation(...)` | `cyberwave/twin/{uuid}/rotation` | Drivers, sims | Payload shapes: [MQTT API Reference](/api-reference/mqtt/main). #### Edge data bus (local, not REST) | SDK | Key expression | | -------------------------------------------- | ------------------------------------ | | `cw.data.publish("joint_states", {...})` | `cw/{twin_uuid}/data/joint_states` | | `cw.data.publish("frames/default", ndarray)` | `cw/{twin_uuid}/data/frames/default` | See [Data Wire Format](/feature-reference/edge/drivers/data-wire-format) for encoding rules. ### Assets, twins, and public catalog entries | Layer | Who controls it | Behavior | | --------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------- | | **Your asset** | Your workspace | Defines the hardware type; twins usually start with asset metadata. | | **Your twin** | Your workspace | `set_schema` updates **this twin's** `metadata["mqtt"]` so you can iterate without changing a shared asset definition. | | **Public Cyberwave assets** | Cyberwave | You can spawn twins from them; use `set_schema` on **your** twin if you need a custom command surface for a private integration. | First-party Cyberwave drivers ship a `cw-driver.yml` in their repositories for reference — you follow the same file format, then apply it to **your** twin with `set_schema` during bring-up. ## Sensor data output If your driver produces sensor data (video frames, depth maps, audio, joint states, etc.), publish it to the **edge data bus** so worker containers and AI models can consume it locally with zero network overhead. There are two options: the **Zenoh data bus** (recommended) and the **filesystem convention** (fallback for constrained environments). Both use the same channel names — a driver can switch between them by changing one env var. ### Option A: Zenoh data bus (recommended) The Zenoh data bus provides zero-copy shared memory between driver and worker containers. Data is consumed directly by worker hooks and `cw.data.latest()`. #### Key expression convention ``` cw/{twin_uuid}/data/{channel} ``` | Segment | Value | Example | | ----------- | ---------------------- | ---------------- | | `cw` | Fixed prefix | `cw` | | `twin_uuid` | UUID of the twin | `a1b2c3d4-...` | | `data` | Fixed namespace | `data` | | `channel` | Canonical channel name | `frames/default` | The `DataBus` handles key composition automatically via `CYBERWAVE_TWIN_UUID`. #### Canonical channels | Channel | Encoding | Pattern | Wire payload | | -------------------- | ------------------ | ------------ | ------------------------------------------------------------ | | `frames/default` | `numpy/ndarray` | Stream | SDK header + raw BGR/RGB uint8 | | `depth/default` | `numpy/ndarray` | Stream | SDK header + raw uint16 depth (mm) | | `joint_states` | `application/json` | Latest value | `{ts, names, positions, velocities?, efforts?, source_type}` | | `position` | `application/json` | Latest value | `{ts, x, y, z, qx?, qy?, qz?, qw?}` | | `audio/default` | `numpy/ndarray` | Stream | SDK header + float32 PCM | | `pointcloud/default` | `numpy/ndarray` | Stream | SDK header + Nx3 float32 | | `imu` | `application/json` | Stream | `{ts, accel: {x,y,z}, gyro: {x,y,z}}` | | `battery` | `application/json` | Latest value | `{ts, voltage_v, current_a, charge_pct}` | | `telemetry` | `application/json` | Latest value | Free-form `{ts, ...}` | You can define custom channels by picking any channel name. #### Python SDK example ```python theme={null} from cyberwave import Cyberwave import numpy as np import os, time cw = Cyberwave(api_key=os.environ["CYBERWAVE_API_KEY"], source_type="edge") # Binary stream: numpy array published with SDK header frame = np.zeros((480, 640, 3), dtype=np.uint8) cw.data.publish("frames/default", frame) # JSON latest-value: dict published as application/json cw.data.publish("joint_states", { "ts": time.time(), "names": ["shoulder_pan", "elbow_flex"], "positions": [0.1, -0.5], }) ``` `CYBERWAVE_TWIN_UUID` is read automatically from the environment. `CYBERWAVE_DATA_BACKEND` selects the transport (`zenoh` or `filesystem`). #### Wire format reference (for native language publishers) For C++, Rust, or any language that needs to publish without the Python SDK: ``` ┌──────────────────┬──────────┬──────────┬─────────────────────┬─────────────────┐ │ header_len (u32) │ ts (f64) │ seq (i64)│ header JSON (UTF-8) │ payload (bytes) │ │ 4 bytes, LE │ 8 bytes │ 8 bytes │ variable length │ variable length │ └──────────────────┴──────────┴──────────┴─────────────────────┴─────────────────┘ ``` Required JSON fields: * `content_type`: `"numpy/ndarray"` | `"application/json"` | `"application/octet-stream"` * `shape`: `[H, W, C]` (for ndarray; omit for JSON/bytes) * `dtype`: `"uint8"` | `"uint16"` | `"float32"` etc. (for ndarray; omit for JSON/bytes) #### C++ native publish example Minimal `zenoh-cpp` snippet that publishes frames with the correct header: ```cpp theme={null} #include #include #include #include std::vector pack_frame( const uint8_t* pixels, size_t pixel_bytes, int height, int width, int channels, double ts, int64_t seq ) { nlohmann::json meta; meta["content_type"] = "numpy/ndarray"; meta["shape"] = {height, width, channels}; meta["dtype"] = "uint8"; std::string json_str = meta.dump(); uint32_t header_len = 16 + static_cast(json_str.size()); std::vector buf(4 + header_len + pixel_bytes); size_t off = 0; memcpy(buf.data() + off, &header_len, 4); off += 4; memcpy(buf.data() + off, &ts, 8); off += 8; memcpy(buf.data() + off, &seq, 8); off += 8; memcpy(buf.data() + off, json_str.data(), json_str.size()); off += json_str.size(); memcpy(buf.data() + off, pixels, pixel_bytes); return buf; } int main() { auto config = zenoh::Config::default_config(); auto session = zenoh::Session::open(std::move(config)); std::string twin_uuid = std::getenv("CYBERWAVE_TWIN_UUID"); std::string key = "cw/" + twin_uuid + "/data/frames/default"; auto pub = session.declare_publisher(key); int64_t seq = 0; while (true) { // ... capture frame into pixels[] ... auto wire = pack_frame(pixels, pixel_bytes, 480, 640, 3, wall_clock_seconds(), seq++); pub.put(zenoh::Bytes(wire.data(), wire.size())); } } ``` The Python SDK's `DataBus.subscribe()` automatically decodes this payload — no adapter code needed. ### Option B: Filesystem convention (fallback) The filesystem convention is the **fallback** for environments where `eclipse-zenoh` cannot be installed. For most drivers, use `cw.data.publish()` (Zenoh data bus) instead — it provides zero-copy shared memory and is consumed directly by worker hooks. Both conventions use the same channel names. Write sensor data to a subfolder of the config directory that Edge Core mounts into your container: ``` $CYBERWAVE_EDGE_CONFIG_DIR/data/{twin_uuid}/{channel}/{sensor_name}/ ``` `CYBERWAVE_EDGE_CONFIG_DIR` is always set by Edge Core (defaults to `/app/.cyberwave`). #### Ring buffer (for stream data) ``` data/{twin_uuid}/frames/default/ ├── ring/ │ ├── 000000.npy │ ├── 000001.npy │ └── ... # numbered slots, wraps around └── meta.json # write pointer + format info ``` **Rules:** * Write `.npy` files to numbered slots: `{slot:06d}.npy` * Slot index = `write_count % buffer_size` (default: 120) * **Atomic writes**: write to `{slot}.npy.tmp`, then `rename()` to `{slot}.npy` * Update `meta.json` after each write #### Latest value (for state data) ``` data/{twin_uuid}/joint_states/ └── latest.json # overwritten each update ``` **Rules:** * Write a single JSON file: `latest.json` * **Atomic writes**: write to `latest.json.tmp`, then `rename()` * Include a `timestamp` field This is a **filesystem convention**, not a Python API. C++, Rust, or any other language can write `.npy` files and JSON to the same paths. ## MQTT topics and payloads If you publish data over MQTT directly (rather than through the SDK's `cw.data.publish`), see the [MQTT API Reference](/api-reference/mqtt/main) for the complete list of topics and payload schemas supported by the platform. That page covers: * Twin transform: position, rotation, scale * Joint state updates (single-joint, flat multi-joint, and aggregated formats) * Navigation commands and status reporting * Locomotion commands (`move_forward`, `turn_left`, etc.) * Telemetry lifecycle events (`connected`, `telemetry_start`, `telemetry_end`) * Sensor data: depth frames, point clouds, metrics * Edge health reporting * WebRTC signalling * Health check ping/pong ## Migrating from MQTT-only drivers If your driver currently publishes sensor data over MQTT, you can add Zenoh publishing without removing the MQTT path. The two paths serve different consumers: * **MQTT** → cloud backend (telemetry, frontend, workflows) * **Zenoh** → local worker containers (zero-copy inference, fusion) ### Step 1: Set CYBERWAVE\_DATA\_BACKEND Ensure `CYBERWAVE_DATA_BACKEND=zenoh` is set in the driver container. Edge Core sets this automatically for managed drivers. For manual testing: ```bash theme={null} docker run -e CYBERWAVE_DATA_BACKEND=zenoh ... ``` ### Step 2: Add cw\.data.publish alongside the MQTT call ```python theme={null} # Before (MQTT only) twin.client.mqtt.update_joints_state(twin_uuid=twin_uuid, ...) # After (dual-publish) twin.client.mqtt.update_joints_state(twin_uuid=twin_uuid, ...) # unchanged cw.data.publish("joint_states", {"ts": ts, "names": [...], "positions": [...]}) ``` Zenoh publish errors are caught and logged — they do not affect the MQTT path. ### Step 3: Verify with a subscriber ```python theme={null} sub = cw.data.subscribe("joint_states", lambda data: print(data)) # Run your driver; you should see joint dicts printed ``` ### Controlling which paths are active Set `CYBERWAVE_PUBLISH_MODE` to choose: | Value | Effect | | ------------ | ------------------------------------- | | `dual` | Both MQTT and Zenoh publish (default) | | `zenoh_only` | Only Zenoh (local-only drivers) | | `mqtt_only` | Only MQTT (legacy mode) | ## Licensing your driver You own your driver code. There are two common paths: * **Open source** — publish your driver as a public repository on GitHub under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0). This is our recommended default and makes it easier for the community to contribute and reuse your work. * **Closed source** — keep your driver proprietary. In this case, we recommend obfuscating your code before distributing the image and including a clear license file that reflects your distribution terms. Interested in writing a closed-source driver? [Reach out to us](mailto:info@cyberwave.com). ## Example driver repositories Fork or read these repositories when building your own compliant driver — each includes a `Dockerfile`, Edge Core env contract, and (where applicable) a `cw-driver.yml`: * **Camera** — [cyberwave-edge-camera-driver](https://github.com/cyberwave-os/cyberwave-edge-camera-driver): USB/RTSP camera as a twin (child of a parent robot twin). * **SO-101 arm** — [cyberwave-edge-so101](https://github.com/cyberwave-os/cyberwave-edge-so101): joint bus + command topic pattern for a manipulator. * **ROS UGV** — [cyberwave-edge-ros-ugv](https://github.com/cyberwave-os/cyberwave-edge-nodes/tree/main/cyberwave-edge-ros-ugv): locomotion and onboard camera profiles under `cw-driver-profiles/`. ## Advanced topics Once you have a working driver, these guides cover the platform features your driver can leverage: Hook-based worker modules for on-device ML inference and event-driven processing. SDK header encoding, key expressions, and the on-wire contract for edge data channels. Time-aware sensor fusion: interpolated point reads and time-window queries. Approximate time synchronizer that fires when samples from all listed channels arrive within tolerance. Capture live edge data to disk and replay it for deterministic debugging. Complete list of MQTT topics and payload schemas: telemetry, commands, navigation, joint states, and more. ## ROS 2 drivers Use **`BaseROS2Driver`** with **`from_ros=`** instead of hand-written MQTT bridges. Full end-to-end lab and success GIFs. What BaseDriver / BaseROS2Driver automate. API, troubleshooting, `ros_publish()` for commands. Protocol stack (TCP, ROS DDS, MQTT) for the UR Sim lab. ## Cartesian pose & dual-arm drivers Set `use_cartesian_pose = True` to expose an absolute `ee_pose` command. By default the raw pose is forwarded to your `_apply_ee_pose(pose, *, arm=None)` seam (implement it to send your robot's native cartesian target). Pass `process_joints_ik=True` to solve IK locally and apply joint targets instead. Set `use_dual_arm = True` and return a `DualArmConfig(left=..., right=...)` from `dual_arm_config()` for a single twin with two arms. Commands are exposed per arm (`left_*` / `right_*`) plus a conjunct `home`; telemetry stays a single combined payload. # Prepare your Jetson Orin Nano Source: https://docs.cyberwave.com/feature-reference/edge/jetson-orin-nano Boot your Jetson Orin Nano from an NVMe SSD, configure headless operation, and set up network failover. This guide covers installing JetPack on your Jetson Orin Nano, using an NVMe SSD for reliable storage, and configuring the Jetson for headless operation with WiFi and optional 5G modem failover. Cyberwave supports **JetPack 6.x and JetPack 7.x**, but we **strongly recommend JetPack 7.2 or later** (L4T r38+, Ubuntu 24.04): some features — including the GPU-accelerated ML worker image — are only available on JetPack 7.x. This guide targets the recommended JetPack 7.2+ path. **Starting with JetPack 7.2, SD card images are no longer supported.** Do **not** flash the Jetson ISO to a microSD card. Write the ISO to a **USB flash drive** instead, then use the installer to write Jetson Linux onto your microSD card or NVMe SSD. **Requirements:** * Jetson Orin Nano Developer Kit * **JetPack 7.2 or later recommended** (L4T r38+, Ubuntu 24.04); JetPack 6.x also works, but some features require JetPack 7.x * **USB flash drive (16GB or larger)** for the JetPack 7.2+ installer ISO * Target storage — a **PCIe NVMe SSD** (recommended for sustained workloads) and/or a microSD card (64GB UHS-1 or larger) * A computer with [Balena Etcher](https://etcher.balena.io/) installed to write the ISO * A DisplayPort monitor, USB keyboard, and mouse for the install SATA SSDs do not work on the Jetson Orin Nano — the M.2 slot only supports PCIe NVMe drives (PCIe 3.0 recommended — PCIe 4.0 may cause issues). *** ## Step 1: Verify board firmware JetPack 7.2 requires JetPack 6.x-generation UEFI/QSPI firmware (version **36.x or newer**). Check your firmware version from the UEFI setup screen. If the Jetson shipped on older factory firmware, complete the JetPack 6.x firmware update path first — see the [official NVIDIA quick start guide](https://docs.nvidia.com/jetson/orin-nano-devkit/user-guide/latest/quick_start.html). The installer will also prompt for a QSPI firmware update during Step 4; make sure to accept it. *** ## Step 2: Write the Jetson ISO to a USB flash drive 1. **Download the Jetson ISO.** Get the JetPack 7.2+ Jetson ISO (e.g. `r39.2`) from the [JetPack download page](https://developer.nvidia.com/embedded/jetpack). 2. **Write it to a USB flash drive.** Open [Balena Etcher](https://etcher.balena.io/), select the ISO, select your USB flash drive (16GB+), and click **Flash**. Simply copying the ISO file onto the USB drive will **not** make it bootable — you must write it with imaging software such as Balena Etcher. And per the note above, the ISO goes on the **USB drive**, never on the microSD card. *** ## Step 3: Install your target storage Power off the Jetson and install the storage you want Jetson Linux written to: * **NVMe SSD (recommended):** install it into the M.2 Key M slot on the underside of the carrier board and secure it with the screw. * **microSD card:** insert it into the slot on the module underside. An NVMe SSD is strongly recommended for any sustained workload — microSD cards degrade over time with frequent writes. *** ## Step 4: Boot the installer and install Jetson Linux 1. Connect a DisplayPort monitor, USB keyboard/mouse, and the installer **USB flash drive**, then power on. 2. Press **Esc** to enter UEFI, open the **Boot Manager**, and select the USB drive. 3. When prompted to update the **QSPI firmware**, press **Y** within 30 seconds to confirm. Allow any UEFI capsule updates to finish — the board may reboot, which is normal. 4. Select your **target storage** (NVMe SSD or microSD card) and confirm. The installer writes Jetson Linux and **handles partitioning and boot configuration automatically** — no manual `dd`, `extlinux`, or partition-resize steps are needed. 5. When it finishes, reboot from the target storage and complete initial setup (accept the EULA, choose language/keyboard/timezone, connect to the network, create your user account). After first boot, select **MAXN SUPER** power mode from the Ubuntu desktop top bar for maximum performance. Verify Jetson Linux is running from your chosen storage: ```bash theme={null} df -h / ``` You should see `/dev/nvme0n1p1` (NVMe) or `/dev/mmcblk0p1` (microSD) as the root filesystem. These steps apply **only to JetPack 6.x**, which still ships an SD-card `.img`. JetPack 7.2+ removed SD-card images — use the installer flow above instead. 1. **Flash the SD card.** Download the JetPack 6.x Jetson Orin Nano Developer Kit SD-card image (`.zip` containing a `.img`) from the [JetPack SDK page](https://developer.nvidia.com/embedded/jetpack), write it to a microSD card with [Balena Etcher](https://etcher.balena.io/), and boot the Jetson from it to complete initial setup. 2. **Install the NVMe SSD** into the M.2 Key M slot and confirm the Jetson sees it with `lsblk` (look for `nvme0n1`). 3. **Flash JetPack to the NVMe** by streaming the SD-card image straight to the drive: ```bash theme={null} unzip -p jetson-orin-nano-devkit-super-SD-image_JP6.2.1.zip | \ sudo dd of=/dev/nvme0n1 bs=4M status=progress conv=fsync ``` 4. **Update the boot configuration** so it points at the NVMe root. Note the PARTUUID (`ls -l /dev/disk/by-partuuid/ | grep nvme0n1p1`), then mount `/dev/nvme0n1p1` and change `root=/dev/mmcblk0p1` to `root=PARTUUID=` in `/boot/extlinux/extlinux.conf`. 5. **Boot from NVMe.** Power off, remove the SD card, and power on. If it drops to the UEFI shell, set the NVMe as the first boot device under **Boot Manager → Boot Maintenance Manager → Boot Options**. 6. **Expand the partition** to fill the disk: ```bash theme={null} sudo parted /dev/nvme0n1 resizepart 1 100% sudo resize2fs /dev/nvme0n1p1 ``` *** ## Step 5: Configure headless operation Switch the boot target from graphical desktop to console-only and enable SSH: ```bash theme={null} sudo systemctl set-default multi-user.target sudo systemctl enable ssh ``` *** ## Step 6: Configure WiFi for headless boot Make your saved WiFi connection available without a user session: ```bash theme={null} sudo nmcli connection modify connection.autoconnect yes sudo nmcli connection modify connection.autoconnect-priority 10 sudo nmcli connection modify connection.permissions "" ``` The `connection.permissions ""` setting is critical — it removes the "only for this user" restriction so the connection activates on boot without anyone logged in. *** ## Step 7: Configure 5G modem failover (optional) If you have a USB 5G modem attached, it may appear as a standard USB ethernet interface. Check with: ```bash theme={null} nmcli device status ``` If you see it connected (e.g. as `usb2` with a `Wired connection` name), set it as a lower-priority fallback: ```bash theme={null} sudo nmcli connection modify "Wired connection 2" connection.autoconnect yes sudo nmcli connection modify "Wired connection 2" connection.autoconnect-priority 5 sudo nmcli connection modify "Wired connection 2" connection.permissions "" ``` Verify routing priorities: ```bash theme={null} ip route ``` WiFi should have a lower metric (higher priority) than the modem. Traffic will automatically fall over to the modem if WiFi drops. *** ## Reboot and verify ```bash theme={null} sudo reboot ``` Wait 30–60 seconds, then SSH in from another machine. If you connect successfully, the Jetson is running headless from NVMe with automatic network connectivity. Your Jetson Orin Nano is now booting from NVMe, running headless, and connecting to the network on boot without manual intervention. ## Step 8: Configure Ethernet for robot connections (if applicable) If you are connecting the Jetson to a robot via Ethernet (e.g., a Unitree Go2), the robot's internal network uses a fixed subnet. Your Jetson's Ethernet interface needs a static IP on that subnet before the robot is reachable. Find the Ethernet interface name: ```bash theme={null} ip a ``` Look for the wired interface (typically `eth0` or `enP8p1s0`). Create a persistent connection with NetworkManager: ```bash theme={null} sudo nmcli connection add type ethernet ifname \ con-name robot-link ip4 192.168.123.11/24 sudo nmcli connection up robot-link ``` Replace `` with your actual interface and `192.168.123.11/24` with an IP appropriate for your robot's subnet (the Unitree Go2 uses `192.168.123.0/24`). This connection will activate automatically on boot. Verify the robot is reachable: ```bash theme={null} ping 192.168.123.161 ``` Without this step, the Cyberwave driver will fail its preflight check with `none of [192.168.123.161, 192.168.12.1] responded on TCP port 9991` because the Ethernet interface has no IP in the robot's subnet. ## Step 9: ML worker image (JetPack 7.2+) Cyberwave ships a Jetson-native ML worker image (`cyberwaveos/edge-ml-worker:-jetson`). On any host where the Cyberwave edge stack detects Jetson hardware, it pulls the `-jetson` tag automatically — no configuration required. The `-jetson` image runs on the entire Jetson Orin family (all `sm_87`), with GPU-accelerated YOLOE, YOLO-World, and ONNX Runtime out of the box. Ultralytics fused-attention ops execute on native sm\_87 kernels — no CPU fallback. ### Supported hardware | Device | Memory | YOLOE variants that fit | | ---------------------- | ---------- | ----------------------------------- | | Orin Nano 4 GB | 4 GB | `yoloe-11n` | | Orin Nano 8 GB | 8 GB | `yoloe-11n`, `yoloe-11s` | | Orin NX 8 GB | 8 GB | `yoloe-11n`, `yoloe-11s` | | Orin NX 16 GB | 16 GB | `yoloe-11n/s/m`, likely `yoloe-11l` | | AGX Orin 32 GB / 64 GB | 32 / 64 GB | any YOLOE variant | Larger models generally need more headroom for KV cache and CLIP text encoder activations; treat the table as a starting point. ### Requirements * **JetPack 7.2 or later** (L4T r38+, Ubuntu 24.04) on any Jetson Orin SKU. The GPU-accelerated `-jetson` ML worker image requires JetPack 7.x — on JetPack 6.x hosts the edge stack still runs, but this worker falls back to CPU. The `-jetson` image ships CUDA 12.9 runtime libraries; the JetPack 7 CUDA 13.x driver (injected at container start) is backward-compatible with them. * `nvidia-container-toolkit` installed and enabled (shipped by default with JetPack via `apt install nvidia-jetpack`). * Roughly **\~9 GB** of free space for the first pull. The image bundles PyTorch, ONNX Runtime GPU, CUDA 12.9 runtime libraries, and cuDNN so the container works on any JetPack 7.2+ Orin host without needing CUDA installed system-wide. Validated on **JetPack 7.2** (L4T r38, CUDA 13.2). The base edge stack runs on JetPack 6.x and 7.x, but the GPU-accelerated ML worker requires JetPack 7.x — so we strongly recommend flashing JetPack 7.2 or later. ### What gets selected On a Jetson host, the Cyberwave edge stack: * Pulls the `-jetson` image variant automatically (instead of the base or GPU variant). * Passes `--runtime nvidia -e NVIDIA_VISIBLE_DEVICES=all -e NVIDIA_DRIVER_CAPABILITIES=all` so the nvidia-container-runtime injects the Tegra iGPU device files and the CUDA driver into the container. * Skips Hailo and discrete-GPU device passthrough. If the `-jetson` tag can't be pulled (e.g. an ad-hoc branch build), the edge stack falls back to the base CPU tag and logs the demotion. Everything keeps running, just on CPU. ### Verifying it's using the Jetson image After the edge service has been up for a minute or two: ```bash theme={null} docker ps --format '{{.Image}}\t{{.Names}}' | grep edge-ml-worker ``` The image tag should end in `-jetson`. To confirm iGPU access from inside the container: ```bash theme={null} docker exec "$(docker ps -q -f name=cyberwave-worker)" \ python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))" ``` You should see `True` and a Tegra device name (for example `Orin`). ### Overriding the auto-selection If you need to pin a specific tag (custom build, hot-fix loop), set `CYBERWAVE_WORKER_IMAGE` in `~/.cyberwave/credentials.json` and restart the edge service: ```json theme={null} { "CYBERWAVE_WORKER_IMAGE": "cyberwaveos/edge-ml-worker:local" } ``` Point at the un-suffixed tag — the edge stack still appends `-jetson` on Jetson hosts. If you're pointing at a private registry outside `cyberwaveos/edge-ml-worker:*`, include the `-jetson` suffix yourself. ### Troubleshooting * **Worker starts on CPU instead of `-jetson`** — check that `/etc/nv_tegra_release` exists on the host and that `docker info` lists the `nvidia` runtime. If both are present but the edge stack still picks CPU, look for a `falling back to` warning in the edge service logs — the `-jetson` image probably failed to pull. * **`torch.cuda.is_available()` returns False inside the worker** — the container is running on CPU. Confirm `NVIDIA_VISIBLE_DEVICES=all` is set in the container env (`docker inspect | grep NVIDIA`), that the container was started with `--runtime nvidia`, and that `nvidia-smi` works from the host. * **Out of memory when loading a YOLOE model** — the model is too large for this Jetson SKU. Consult the sizing table above; either downshift to a smaller variant (`yoloe-11n` / `yoloe-11s`) or move the workload to Orin NX / AGX. * **Very slow first start** — the image is \~3–4 GB and Jetson NVMe throughput on first pull can be modest. Subsequent restarts reuse the local layer cache. # macOS microphone bridge Source: https://docs.cyberwave.com/feature-reference/edge/macos-microphone Run the generic microphone driver in Docker on a Mac by bridging host CoreAudio through ffmpeg and HTTP PCM. Docker Desktop on macOS runs **Linux** containers. Those containers cannot open CoreAudio or `/dev/snd` the way a Linux edge host can. Cyberwave mirrors the [camera MJPEG bridge](/feature-reference/edge/overview) pattern: **host `ffmpeg` captures AVFoundation audio** and serves **raw PCM over HTTP**; the **microphone driver container** reads that URL via `AudioBridgeCapture` instead of PortAudio. ## Architecture ```text theme={null} Mac host (CoreAudio / AVFoundation) └─ ffmpeg LaunchAgent com.cyberwave.audio-stream* └─ HTTP PCM :8101+ (host.docker.internal from container) └─ generic-microphone driver (Docker) └─ WebRTC + Zenoh → twin / media-service ``` | Layer | Artifact | | ------------- | -------------------------------------------------------------------------- | | Host capture | `ffmpeg` + AVFoundation, managed by `launchctl` | | Per-twin map | `~/.cyberwave/audio_streams.json` → `twin_to_stream_url` | | Container env | `CYBERWAVE_METADATA_AUDIO_DEVICE=http://host.docker.internal:8101` | | Edge-core | Probes ports `8101`–`8110` on Darwin; injects URL when starting the driver | On **Linux** Docker hosts, skip the bridge: Edge Core bind-mounts `/dev/snd` and the driver uses PortAudio/ALSA directly. See [Native microphone driver — Linux](/feature-reference/edge/drivers/native-microphone-driver#linux-audio-notes). ## Prerequisites * **Docker Desktop** installed and running (daemon up before `cyberwave edge install`). * **`ffmpeg`** on the Mac host (the CLI installer expects it on `PATH`). * A **microphone twin** linked to this edge (catalog `generic-microphone` asset). * **Microphone privacy** granted to the terminal or process running `ffmpeg` when macOS prompts. ## First-time setup 1. Install the CLI and Edge Core (pairing flow): ```bash theme={null} curl -fsSL https://cyberwave.com/install.sh | bash sudo cyberwave pair ``` 2. During `cyberwave edge install` on macOS, the installer: * Lists AVFoundation input devices and prompts for a microphone (by **index**; stored in `audio_streams.json`). * Installs a LaunchAgent (`com.cyberwave.audio-stream`) on port **8101** (additional mic twins use `8102`, …). * Writes `~/.cyberwave/audio_streams.json` with `twin_to_stream_url` entries. * Restarts Edge Core so driver containers receive `CYBERWAVE_METADATA_AUDIO_DEVICE`. 3. Link your microphone twin to the edge in the Cyberwave UI, then restart if you added the twin after install: ```bash theme={null} sudo cyberwave edge restart ``` ## Switch microphone or fix a broken bridge Re-run selection without a full reinstall: ```bash theme={null} sudo cyberwave edge install --reconfigure-microphone ``` Skip the interactive picker when you already know the AVFoundation index: ```bash theme={null} sudo cyberwave edge install --reconfigure-microphone --microphone-index 0 ``` `cyberwave edge restart` also **self-heals** silent ffmpeg slots (`launchctl kickstart -k` on `com.cyberwave.audio-stream*`) and warns when `audio_streams.json` references a port with no running service — same pattern as the camera bridge. ## Verify ```bash theme={null} # Host bridge listening lsof -i :8101 # Persisted twin → URL map cat ~/.cyberwave/audio_streams.json # Driver should show HTTP bridge, not "0 input devices" cyberwave edge logs -f ``` **Healthy container logs** (MQTT/backend errors aside): ```text theme={null} Resolved macOS host audio bridge for microphone capture: http://host.docker.internal:8101 Configuring microphone driver (..., selector='http://host.docker.internal:8101', ...) Using host HTTP audio bridge ``` **Failure signals:** | Symptom | Likely cause | | ---------------------------------- | ----------------------------------------------------------------------------------------- | | `Discovered 0 input devices` | Bridge URL not injected — re-run `--reconfigure-microphone` and `edge restart` | | `PortAudio not initialized` | Driver probed ALSA inside Docker — fixed when bridge URL is set (recent driver) | | Connection refused to backend/MQTT | Cloud stack not running — start your Cyberwave backend; audio bridge can still be correct | ## `audio_streams.json` shape ```json theme={null} { "twin_to_stream_url": { "c349694f-0947-421e-9fe0-820e24dc7e96": "http://host.docker.internal:8101" }, "device_index": 0, "sample_rate": 48000, "channels": 1 } ``` Edge-core reads this file (and TCP-probes the port) when launching each `generic-microphone` container. The driver does **not** enumerate PortAudio devices on macOS Docker when the bridge URL is present. ## Local debugging without Docker Run the driver on the host with direct PortAudio (no HTTP bridge): ```bash theme={null} cd cyberwave-edge-runtime/runtime-services/drivers/native/cyberwave/generic-microphone ./run-local.sh ``` ## Related WebRTC, recording, Zenoh, and env var reference. macOS edge install, camera bridge, and CLI lifecycle. Playback counterpart — macOS uses a host PCM **sink** on port `8201` (same bridge pattern). # Overview Source: https://docs.cyberwave.com/feature-reference/edge/overview Cyberwave Edge Core acts as the orchestrator of Cyberwave edge drivers. Cyberwave Edge Core acts as the orchestrator of Cyberwave edge drivers. Public repository: [cyberwave-os/cyberwave-edge-core](https://github.com/cyberwave-os/cyberwave-edge-core) ## Use Cyberwave Edge with the CLI SSH to the edge device where you want to install Edge Core, then install the Cyberwave CLI and run the installer: `cyberwave pair` is the recommended top-level alias for `cyberwave edge install`. Both run the same first-time setup flow. **Prerequisites by platform**: * **Linux**: Docker is auto-installed via `apt-get` when missing (Ubuntu / Debian / Raspbian). * **macOS**: Docker Desktop must be installed and running before `cyberwave edge install` (the installer aborts early with a hint if not). The Rust toolchain is auto-installed via `rustup` (with confirmation) when missing — it is needed to compile the USB/IP server used for USB device passthrough. Manage the edge node service lifecycle, configuration, and monitoring: | Subcommand | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | `install` | Install cyberwave-edge-core and register systemd service. On macOS, also sets up the camera stream bridge and prompts for camera selection. | | `install --reconfigure-camera` | Re-select camera and restart the stream and edge-core without a full reinstall | | `start` | Start the edge node | | `stop` | Stop the edge node | | `restart` | Restart the edge node (systemd or process) | | `status` | Check if the edge node is running | | `logs` | Show edge node logs | | `driver` | Manage edge driver containers (subgroup) | Want to check how fast an edge device actually is? Run [`cyberwave edge bench`](/feature-reference/workflows/workers/bench) to micro-benchmark the Zenoh SDK hot paths and compare against a per-device baseline. *** ## Host telemetry Every `edge_health` heartbeat carries the host's dynamic resource pressure alongside the per-stream health it has always carried: * `host_memory_percent`, `host_memory_available_mb` * `cpu_temp_c` * `consecutive_critical` — reconcile cycles where memory or CPU sat above the critical threshold; resets when pressure clears * `watchdog_layers` — e.g. `["systemd"]` on a developer laptop or `["systemd", "hardware"]` on a Raspberry Pi with `/dev/watchdog` Driver containers see their container's `/proc`, not the host's, and omit these fields. Only the bootstrap publisher running on the edge host populates them. Static hardware identity — total RAM, CPU model, kernel, thermal source, hardware-watchdog availability — is uploaded via `POST /api/v1/edges/discover` and stored on `Edge.metadata.host_facts`. The first POST runs synchronously at startup; a background daemon then re-POSTs every \~30 s so the backend can tell "edge daemon alive" apart from "edge daemon dead" even when no twin MQTT traffic is flowing. The Edge Devices tab renders both signals: a colour-coded pressure pill from the live heartbeat plus a "what hardware is this" row from the REST identity. The REST keepalive powers a three-state liveness pill — **Online** (twin MQTT activity), **Idle** (edge alive, no twin work; `liveness_state="standby"` on the wire), **Offline** (neither signal within window). Idle is what shows up on a freshly-paired edge that hasn't had any twins bound to it yet: previously such an edge would render as "Offline" even though `edge-core` was running fine. The Edge Devices tab sorts rows by liveness — online → idle → offline → unresolved binding — so working edges land at the top and broken bindings sink to the bottom. Static facts work on both Linux and macOS: Linux reads `/proc/{meminfo,cpuinfo}` and `/sys/class/thermal`; Darwin shells out to `sysctl` for RAM, CPU model and (logical) core count. Dynamic host pressure (memory %, CPU temp) remains Linux-only for now — the dashboard hides the pressure pill on macOS edges and shows only the static identity row, and `thermal_source` is omitted on macOS so it never claims a sensor that isn't being sampled. *** ## Per-stream configuration Each entry under `streams[id]` in an `edge_health` heartbeat carries an optional typed `stream_config` block describing the runtime-negotiated config for that stream. The block is a discriminated union keyed by `kind`: ```json theme={null} { "streams": { "rgb-0": { "stream_config": { "kind": "camera", "source": "/dev/video0", "resolution": "1280x720", "fps": 15, "camera_type": "cv2" } }, "audio": { "stream_config": { "kind": "audio", "sample_rate_hz": 48000, "channels": 2, "codec": "opus" } }, "lidar-front":{ "stream_config": { "kind": "lidar", "source": "/point_cloud2", "scan_rate_hz": 10 } } } } ``` Drivers attach a block one of two ways: * `EdgeHealthCheck.register_stream_config(stream_id, config)` for static configs known at startup; the publisher keeps the snapshot and merges it into every heartbeat. The Go2 `lidar_bridge.py` and `pointcloud_bridge.py` use this path because the scan rate is wired from a ROS parameter at node bootstrap. * `EdgeHealthCheck(..., stream_config_provider=callable)` for dynamic configs where some fields are only known after streamer startup (post-V4L2 `actual_fps`, post-handshake codec, ...). The callable is invoked on every heartbeat and its values override registered statics on key collision. `MicrophoneAudioStreamer` and `MultimediaStreamer` use this path so re-opening a mic at a different sample rate is reflected on the very next heartbeat without re-registration. `MultimediaStreamer` keys its audio block under `"audio"` rather than the legacy `"stream"` placeholder so a future video `get_stream_config` hook can slot in next to it as `"video"` without a wire-breaking rename. `register_stream_config` enforces a per-kind required-field contract: `kind: "camera"` must carry `source`, `resolution`, `fps`; `kind: "audio"` must carry `sample_rate_hz` and `channels` (and may optionally carry `codec` and `source`); `kind: "lidar"` requires `source` and `scan_rate_hz` (`points_per_second` is optional and intentionally omitted by both Go2 bridges because the only available value is the post-downsample cap, not measured throughput); `kind: "imu"` requires `source` and `rate_hz`. Unknown kinds pass through additively. URL-shaped `source` values must have `user:pass@` stripped before they reach the wire — the SDK's `CV2CameraStreamer` does this automatically for RTSP and HTTP sources. `kind: "audio"` deliberately treats `source` as optional: across the rest of the SDK `source` is a device path / URL / ROS topic, and a WebRTC microphone has no equivalent (publishing the host ALSA / CoreAudio device path would leak operator-local filesystem state). Liveness — `frame_count` vs `mark_alive`. Camera and lidar publishers call `EdgeHealthCheck.update_frame_count()` per emitted frame so the wire-side `fps` / `frames_sent` numbers carry meaning to operators (frames per second is the standard quality signal for both). Audio publishers — and future IMU / encoder / GPS publishers — call `EdgeHealthCheck.mark_alive()` instead, which advances the staleness clock without bumping the counter. Reporting `fps: 50.0` for a microphone emitting 20 ms Opus packets would be terminology-correct but operationally noise; the dashboard already hides those fields for audio rows, but raw MQTT subscribers and the analytics table see the cleaner shape too. `mark_alive` still flips `ice_connection_state` to `connected` on first call so audio rows render `connected` from the first heartbeat onward. A top-level `camera_config` slot remains populated for one deprecation release for out-of-tree consumers that still read the legacy single-camera shape. New consumers must read `streams[id].stream_config` instead — the legacy slot only ever covers one camera and is silent for audio / lidar / IMU streams. When more than one camera-kind `stream_config` is registered, the legacy slot deterministically reflects the lexicographically-smallest `stream_id` so multi-camera devices don't flap identities heartbeat-to-heartbeat. An idle publisher that has registered no `stream_config` and has never seen a frame emits an empty `streams: {}` map, `stream_count: 0`, and `camera_config: null`. This is the wire shape the edge-core bootstrap publisher uses in the gap before a driver container starts — the dashboard's Edge details renders nothing for streams in that case, rather than a phantom `"stream"` row that flickers away the moment a real driver takes over. Once a driver starts publishing (either by registering a `stream_config` or by ticking `update_frame_count()`), the entry appears on the next heartbeat. The dashboard's per-row renderer falls back to the asset's declared `parameters.{width, height, update_rate}` for camera streams when neither the wire `stream_config` nor the legacy `camera_config` carries that data, so paired cameras still show their target resolution and fps before the live stream catches up. *** ## Upgrading Edge Core ships the orchestrator binary and a systemd unit file. From the high-availability watchdog release onward the unit uses `Type=notify` and the binary issues a `READY=1` notification at startup — the two must match. When upgrading on an existing device, re-run `sudo cyberwave edge install` after the package upgrade to regenerate the systemd unit. Skipping this step results in one of two states: * **Old binary, new unit (`Type=notify`):** systemd waits the full `TimeoutStartSec` (900 s) for a `READY=1` that never arrives and marks the service failed. * **New binary, old unit (`Type=simple`):** the service runs, but `WatchdogSec`/`OOMScoreAdjust`/`TimeoutStartSec` are not in effect — no watchdog protection. The Debian package post-install script regenerates the unit automatically, but manually installed binaries (e.g. `pip install cyberwave-edge-core` then `cyberwave edge install`) require the manual step. *** ## Related Control robots in real time through Edge Core From a twin to your real hardware Write and manage hardware drivers # Prepare your Raspberry Pi Source: https://docs.cyberwave.com/feature-reference/edge/raspberry-pi Flash the Cyberwave OS image to an SD card, configure Wi-Fi via the captive portal, and SSH into your Pi. The Cyberwave Raspberry Pi image is a pre-built SD card image based on Raspberry Pi OS Lite (Bookworm) with Wi-Fi onboarding, SSH, Docker, and mDNS pre-configured out of the box. Insert the SD card and power on — the Pi is ready to use without any manual setup. **What's included:** * Raspberry Pi OS Lite (Bookworm) — available for **64-bit (arm64)** and **32-bit (armhf)** * SSH enabled on first boot (`pi` / `cyberwave`) * Hostname `cyberwave`, reachable at `cyberwave.local` via mDNS * Docker Engine pre-installed * Wi-Fi captive portal onboarding ([WiFi Connect](https://github.com/balena-os/wifi-connect)) *** ## Step 1: Download and Flash Choose the variant that matches your Raspberry Pi model: | Variant | Compatible models | | ------------------ | -------------------------------- | | **arm64** (64-bit) | Raspberry Pi 4, 5, Zero 2 W | | **armhf** (32-bit) | Raspberry Pi 3, Zero W, Zero 2 W | The Raspberry Pi Imager handles downloading, flashing, and verification in one step. Works on macOS, Windows, and Linux. 1. Download and install [Raspberry Pi Imager](https://www.raspberrypi.com/software/). 2. In your browser download the image for your board: * [Raspberry Pi 4, 5, Zero 2 W](https://static.cyberwave.com/iso_images/cyberwave-rpi-arm64-latest.img.xz) * [Raspberry Pi 3, Zero W](https://static.cyberwave.com/iso_images/cyberwave-rpi-armhf-latest.img.xz) 3. Insert your SD card. 4. Open Raspberry Pi Imager. 5. Click **Choose OS** → scroll to the bottom → **Use custom**, then select the `.img.xz` file you downloaded. No need to decompress it first. 6. Click **Choose Storage** and select your SD card. 7. Click **Next**. If asked about OS customisation, choose **No** — the Cyberwave image already has SSH and a default user pre-configured. 8. Click **Write** and wait for the flash and verification to complete. Double-check the storage device before writing. All data on the selected device will be permanently erased. Download the image with `wget`, decompress it, then write it to the SD card with `dd`. ```bash theme={null} # 64-bit — Raspberry Pi 4 / 5 / Zero 2 W wget -O cyberwave-rpi-arm64.img.xz "https://static.cyberwave.com/iso_images/cyberwave-rpi-arm64-latest.img.xz" # 32-bit — Raspberry Pi 3 / Zero W wget -O cyberwave-rpi-armhf.img.xz "https://static.cyberwave.com/iso_images/cyberwave-rpi-armhf-latest.img.xz" ``` Decompress the image: ```bash theme={null} xz -d cyberwave-rpi-arm64.img.xz # or armhf ``` **macOS:** ```bash theme={null} # Identify your SD card by size diskutil list sudo diskutil unmountDisk /dev/diskN sudo dd if=cyberwave-rpi-arm64.img of=/dev/rdiskN bs=4m ``` **Linux:** ```bash theme={null} # Identify your SD card by size lsblk sudo dd if=cyberwave-rpi-arm64.img of=/dev/sdX bs=4M status=progress conv=fsync ``` Replace `/dev/diskN` (macOS) or `/dev/sdX` (Linux) with your actual SD card device. Using the wrong device will overwrite that disk entirely. Confirm the device name carefully before running `dd`. *** ## Step 2: Configure Wi-Fi 1. Insert the SD card into the Raspberry Pi and power it on. 2. **If the Pi already knows a Wi-Fi network** it will join it automatically — skip to Step 4. 3. Otherwise the Pi creates a setup hotspot: * **SSID:** `Cyberwave-Setup` * **Password:** `cyberwave` 4. Connect your laptop or phone to the wifi network `Cyberwave-Setup`. 5. The captive portal opens automatically on most phones and laptops. If you don't get the modal of the captive portal, manually go to `http://192.168.50.1`. Use **Safari** or **Firefox** for this step. Chrome may block local HTTP pages when the active network has no internet, which prevents the portal from loading. On macOS, a **"Sign in to network"** notification may appear — clicking it opens the portal directly. 6. Select your Wi-Fi network from the list and enter the password. 7. The Pi connects, then reboots automatically. *** ## Step 3: SSH into the Pi After the reboot, the Pi is on your local network and reachable via mDNS: ```bash theme={null} ssh pi@cyberwave.local # Password: cyberwave ``` If `cyberwave.local` does not resolve, look up the Pi's IP address in your router's DHCP table and connect directly: ```bash theme={null} ssh pi@ ``` You are now connected to your Raspberry Pi. Docker is installed and running, SSH is open, and the Pi is reachable at `cyberwave.local` on your local network. ## Next steps You are now ready to use your Raspberry Pi with Cyberwave. Next, [install the CLI and pair a device](/overview/tools/cli#pair-a-device). # Editing a universal schema Source: https://docs.cyberwave.com/feature-reference/edit-universal-schema Edit an asset's or twin's structure as JSON directly in the app The **universal schema** is what a robot *is* — its links, joints, sensors, actuators and capabilities. Assets and twins each carry one, and both can now be edited as JSON from the app by anyone with write access. ## Where to find it **Asset** — open the asset, go to the **Files** tab, and choose **Edit JSON** on the Base schema card. **Twin** — select the twin in the environment editor, open **Advanced**, and choose **Schema JSON**. ## What gets checked before a save lands The editor checks the JSON parses and is an object, and reports the line and column when it does not. On save, the server validates the whole document — capabilities, and a cross-check that any drive block names joints that actually exist. A schema that fails is refused with the reason, and nothing is written. Two shapes are always refused: an empty schema, and one that drops `links` when it previously had them. Removing `sensors` or `actuators` is a normal edit and is allowed. For an asset, some checks report rather than refuse. Your edit is saved and the editor lists what it found, so you can fix it in a follow-up edit instead of being blocked. Removing links or joints asks for confirmation first. They are what the 3D viewer and the simulation exporter walk, so removing them changes what every twin of that asset resolves to. ## If someone else edits at the same time The editor remembers which version of the schema you opened. If someone saves a change before you do, your save is refused rather than overwriting theirs — close and reopen the editor to load the current schema, then reapply your edit. ## What a rebuild or a sync discards **Assets** — regenerating the schema from the URDF keeps per-joint home positions, sensors, actuators, capabilities and collision config. Anything else you edit by hand is discarded on the next rebuild. **Twins** — a twin's schema is its own snapshot of its asset. Running **sync with asset** re-snapshots it and discards edits made here, apart from sensor fields you changed and joint homes you authored. Editing a twin's schema never changes its asset. ## Moved joint zeros If an edit changes a joint's `pose` or `axis`, it moves that joint's zero. Saved joint positions and home positions are offsets from that zero and are **not** adjusted to match, so they will refer to a different physical pose afterwards. The editor says so when it happens — re-teach those positions rather than assuming they carried over. # Assistant asset generation Source: https://docs.cyberwave.com/feature-reference/environment-editor/assistant-asset-generation Create and revise private URDF assets while continuing to edit an environment The [environment assistant](/ai/environment-assistant) can create a private URDF asset when catalog search and procedural primitives do not satisfy the request. Asset work runs asynchronously, so you can enter the editor and continue arranging the scene while the asset builds. In edit mode, **Create an object with the agent** opens an editable assistant request. **Prepare a training scene** starts with the robot, task and objects it will interact with, then checks placement, collisions, physics and camera framing. The shared **Add asset** dialog also offers direct description, file and photo creation. [Compare these choices](/feature-reference/create-asset). ## Create an asset Describe the environment normally. The assistant searches the catalog first, uses a procedural primitive for simple geometry, and requests generation only when a supported programmatic builder precisely represents the requested object. It does not insert a placeholder catalog twin. The sidebar and 3D scene show the asset's build state. **Stop build** cancels the run independently from **Edit while build continues**. The visible stages are **waiting**, **planning**, **building geometry**, **preparing simulation data**, **checking articulation**, and **validating**. A completed build may continue rendering its preview without blocking environment editing. A workspace accepts at most three active generation runs per user; another request remains unavailable until one finishes or is stopped. ## Revise an asset Select a twin and describe the desired result, such as changing geometry, adding articulation, or adjusting animation timing. The existing asset remains unchanged while a private candidate is generated and validated. When the preview is ready, accept it to swap the selected twin to the new revision. Only the newest revision attempt is actionable. Accepting a newer candidate supersedes older failed or stale attempts. Assistant-created assets start private and scoped to the environment that requested them. Direct description creation can also save to the catalog without a scene, and offers an explicit Private/Public choice. Use the existing asset visibility and sharing controls to promote a validated asset to a workspace, organization, link, or public audience; generation does not bypass those permissions. ## Supported representations Catalog and generated assets are considered visually usable when they provide at least one supported 3D representation: GLB, Gaussian splat, or URDF. An asset without any supported representation appears as a simple proxy and is not treated as a suitable catalog match. ## Coordinate-frame compatibility Environment poses represent the asset's semantic root frame. URDF visuals are not recentered around their visual bounds in the environment editor. This keeps grounding, docking, transforms, physics, and simulation exports aligned. Assets authored around a visual-center assumption may therefore appear shifted and should be migrated by correcting their URDF root transform or grounding metadata. The coordinate grid is depth-tested scene decoration: geometry in front of the grid occludes it, and the grid does not participate in pointer picking. # Disabling collision on a twin Source: https://docs.cyberwave.com/feature-reference/environment-editor/disable-collision Make a twin visible but non-solid, in the editor and in simulation. Some twins are there to be seen, not to be hit — a floor marking, a reference model, a piece of scenery a robot is meant to drive straight over. **Disable collision** makes a twin non-solid while keeping it fully visible. ## Where to set it Select the twin in the environment editor, open the **Appearance** section, and turn on **Disable collision**. The summary chips above the section show **Collision off** while it is set. ## What changes * **The visual mesh still renders.** Disabling collision never hides the twin. * **Other twins pass through it** in the editor's physics preview. * **Exported simulation scenes agree.** The twin's collision shapes are still exported, but they take part in no contact, so nothing collides with it in MuJoCo either. ## Things worth knowing * **This is per twin, not per asset.** Two twins of the same asset can differ; the catalog asset is unchanged. * **It is not a fix for a bad collision mesh.** If a twin blocks more space than its shape suggests, the cause is usually a coarse collision shape in the asset. Disabling collision hides that rather than correcting it — prefer fixing the asset's collision geometry when other objects need to interact with it at all. * **It is independent of Fixed base.** Fixed base decides whether a twin *moves* under physics; disable collision decides whether anything can *touch* it. * **A free-base twin with collisions off falls through the floor.** Nothing can stop it, including the ground. Use it on fixed-base twins, or on twins whose pose is driven rather than simulated. # Driver logs Source: https://docs.cyberwave.com/feature-reference/environment-editor/driver-logs Read what your drivers are saying, across every robot in the environment, from the Logs tab. The **Logs** tab in the environment workbench shows the log lines your edge drivers emit, for every robot in the environment at once. It is where you look when a driver started but nothing moved, or a camera stream never appeared. ## Reading the tail Lines arrive **newest first**, so the most recent one stays at the top of the list instead of scrolling away as new lines land. Use the sort button in the toolbar to flip to oldest-first if you would rather read a startup sequence in order. Each line carries a coloured left edge for its severity — red for errors, amber for warnings, green for info, grey for debug — so you can pick the errors out of a busy list without reading every message. The level is also named beside the robot, so it is there when the colour is not enough and it is matched by **Search**. ## Choosing a time range The **Range** control sets what the tab reads: * **Last 5 min** (the default) — a live tail of what is happening now. * **Last hour** / **Last 24 hours** — for something you have already missed. * **Custom…** — a fixed start and end. A fixed range is not a tail, so the tab loads it once and stops refreshing. A shorter range is faster to load. Start narrow and widen only when you need to look further back. ## Knowing when there is more The counter above the list reads, for example, `40 of 200+ loaded` — how many lines are on screen after your search and level filters, and how many have been loaded from the range. A trailing `+` means the range holds more lines than are loaded. When that happens, **Load older** at the bottom of the list fetches the next page. ## Narrowing it down * **Twin** — read one robot instead of the whole environment. * **Level** — show only the severities you care about. * **Search** — match on message text, robot name, or anything in the line's details. * **Download** — save every loaded line as JSON, filters included or not. Click the info icon on any line for its full payload: container name, driver image, edge-core and SDK versions, and the raw metadata the driver sent. # Environment templates Source: https://docs.cyberwave.com/feature-reference/environment-editor/environment-templates Discover reusable setups by use case and create your own environment ## Explore a use-case template Template cards show the saved environment, included twins and workflows. Use the use-case filter and search to find a relevant setup. Public pages show public templates; signed-in users can also discover templates available through their existing access. Open a card to inspect its contents. **Play tour** highlights twins at their saved positions in a lightweight schematic; **Next twin** steps through them manually. The tour is a visual preview, not a simulation result or a hardware command. ## Start using a template Select **Use template**, sign in if needed, and choose the destination workspace or project in the existing creation dialog. Confirm the template to create your own environment. The source remains unchanged. Cloning a setup does not provision physical hardware, establish edge connections or run its workflows. Review the copied configuration and connect the intended devices before operating the physical use case. ## Organize templates With write access to an environment, open **Environment settings**: 1. Enable **Reusable environment template**. 2. Enter comma-separated **Use cases**, such as `material-handling, inspection`. 3. Save the settings. Other tags you have added are preserved. The existing sharing controls determine who can discover and clone the template; marking an environment as a template does not make it public. # Fixed and free-floating objects Source: https://docs.cyberwave.com/feature-reference/environment-editor/fixed-base-objects Decide whether a procedural object stays put or moves under physics in simulation. Every procedural object you place — a wall, a rack, a crate — is either **fixed base** (welded to the world) or **free base** (a physical body that falls under gravity and can be pushed). ## Where to set it Select the object in the environment editor. The right-hand panel has a **Physics** section with a **Fixed base** switch: * **On** — the object stays exactly where you placed it, no matter what hits it. * **Off** — the object is simulated: it drops onto whatever is beneath it, and robots or other objects can move it. **Reset** puts it back to the default for that kind of object. Fixtures (walls, racks, floors, tables) default to fixed; loose objects (boxes, spheres, cylinders, pallet stacks, carts) default to free. ## What changes in simulation * A **free** object gets a free joint in MuJoCo, so it obeys gravity and contacts. Its live pose is streamed back, and the 3D scene follows it. * A **fixed** object is welded to the world. Its pose is a constant, so nothing is streamed for it. * The editor's own physics preview follows the same setting once you enable the physics toggle in the viewport. ## Things worth knowing * **A freed fixture is still heavy.** Freeing a concrete wall or a loaded pallet rack is allowed, and it will topple or slide once the simulation starts. * **Very thin objects cannot be freed usefully.** A marker with essentially no volume has no mass to simulate, so it stays welded — the editor warns you when this happens. * **The setting sticks.** Switching an object to a different template keeps your choice; use **Reset** if you want the new template's default instead. ## Setting it from an agent `cw_create_procedural_primitive` takes a `fixed_base` argument, and `cw_edit_environment` can change it on an existing object. Leave it out to inherit the default for that kind of object. # Generate a map from the scene Source: https://docs.cyberwave.com/feature-reference/environment-editor/generated-occupancy-map Build a 2D occupancy grid from the geometry you authored, so a robot can navigate before it has ever mapped the site. ## What this is for Normally a map exists because a robot drove around and built one. **Generate from scene** goes the other way: it turns the walls, shelves and floors you placed in the editor into the same kind of 2D occupancy grid, without a robot and without a mapping run. Use it to plan routes in a site you have modelled but not yet visited, to give a robot something to localize against on its first run, or to compare against a real SLAM map of the same building. Find it under **Maps** in the right panel in **Edit**, after laying out the site. The **Simulation** panel focuses on simulation settings and sensor previews. ## Step-over height The most important setting, and the one that makes the map robot-specific. A 6 cm cable rail across the floor is an obstacle for a wheeled AMR and a non-event for a quadruped that simply steps over it. So the map is not a property of the environment alone — it depends on which robot is driving. **Step-over height** is the clearance below which objects are left out of the grid. Pick a robot from the dropdown and it fills the field in: from that robot's own declared dimensions if it has them, otherwise from a default shared by every robot of that type. The field says which, so check it against the real machine when it is the shared default. Override it if you want. **Robot height** does the same at the top end, so ceilings and overhead gantries the robot passes under are left out too. Both fields are under **Advanced**. Because the map depends on the robot, generating for a second robot with a different clearance creates a **second map** rather than replacing the first. Regenerating for the *same* robot replaces its map in place. ## Nothing is dropped silently Objects left out of the grid are still reported. After generating you get a list of what was stepped over and what was passed under, with heights — so a clear corridor on the map is always explicable. Anything else worth knowing about the result appears there too: a doorway that did not cut through its wall, objects that fell outside the map area, a scene mapped without a floor, or a map that was **not** made the environment's navigation reference because an existing alignment would have been overwritten. ## Preview before you commit The preview updates as you change the settings and stores nothing. Lower the step-over height and the floor rails reappear; raise it and they vanish. Generate only once it looks right. ## What you get An ordinary occupancy grid, marked **Generated** in the map list so it is never mistaken for a surveyed one. It shows in the 3D scene like any other map, and it becomes the environment's navigation reference so waypoints line up with it without any manual alignment. If you had already aligned a real SLAM map by hand, that alignment is left alone and you are told so. The **Navigation reference** label identifies the environment's saved map. **Show in scene** only changes which map you see. A robot may use its own map when its navigation configuration specifies one. A generated map is not enough for a Unitree Go2 to find itself after a restart. The Go2 relocalizes from a map it recorded itself, with a printed AprilTag in view. See [AprilTag relocalization](/robots/go2-apriltag-relocalization). Doors and windows placed as openings are cut out of the walls they sit in, so routes can pass through them. ## Requirements * The environment needs some geometry to rasterize. With nothing to bound a map with, generation is refused. * A **floor** (a ground or terrain object) is recommended but not required. Without one the map assumes open ground — the same floor the simulator adds — and says so. That is fine in simulation and optimistic on a real site, which has boundaries the model does not. * Aerial robots are not supported: a flat floor slice cannot describe what a drone flies over or under. # Geo reference Source: https://docs.cyberwave.com/feature-reference/environment-editor/geo-reference Place a real site on Earth so a robot's GPS puts it in the right spot in your scan. ## What this is for You have a scan of a real place — a factory, a yard, a warehouse — and a machine moving around inside it that reports GPS. The machine knows where it is on Earth. Your scan does not. A **geo reference** tells the environment where on Earth its origin sits, which lets the two be reconciled: the robot appears in the right aisle, in real time, in your point cloud. **Live mode only.** GPS is not simulated. In Simulate and Edit a GPS-positioned twin sits at its saved position. ## Set the geo reference In **Edit** mode, right panel → **Geo Reference**: | Field | What it means | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Latitude / Longitude** | WGS-84 coordinates of the environment's origin — the point where the scene's X and Y are both zero. | | **Altitude** | The altitude of the environment's floor (where Z is zero). | | **Altitude datum** | Whether that altitude is mean sea level or ellipsoidal height. This is recorded, not converted — match whatever your receiver reports, because the two differ by tens of metres. If you do not know, pin the twin to the reference plane instead (below). | | **Heading** | The compass bearing, clockwise from true north, of the scene's +Y axis. `0°` means +Y points true north. If your floor plan is rotated relative to north, this is the field that fixes it. | Save, and the reference applies to every GPS-positioned twin in the environment — they move to the corrected coordinates straight away, without waiting for their next fix. Cloning an environment keeps the numbers but marks the reference as needing confirmation, so a copy of a site cannot silently claim the original's coordinates. Re-confirm and save before flying in the clone. ## Show the map under your scene Once the environment has a geo reference, you can put real-world imagery on the ground beneath it. **View → GPS map**, or the globe button in the toolbar. The map is turned to match your **Heading**, so scene north is real north. Twins, waypoints and areas sit on top of it, which makes it the quickest way to confirm a geo reference is actually right: pick a feature you recognise — a building edge, a road, a fence line — and check the scene lines up with it. If the whole scene looks rotated against the imagery, the Heading is wrong. It opens **straight down**, as a plan view. That is the view to place and check points in: looking at the map from an angle puts the sides of buildings between you and the ground, and a point you click can land metres from where you meant. Pan and zoom as much as you like — the view stays flat until you ask for a tilted one. Available in **Edit**, **Simulate** and **Live**. Unlike GPS *positioning*, the map needs only the geo reference, not a live fix, so it works in all three. | Option | What it does | | --------------- | ------------------------------------------------------------------------ | | **Map imagery** | Satellite, satellite with labels, road map, or terrain. | | **Opacity** | Fade the imagery back so scene geometry reads more clearly on top of it. | There is no size or extent to set: pan and zoom the map and it loads the ground you are looking at. Without a geo reference the toggle stays disabled — there is nowhere on Earth to put the imagery yet. Set the reference above and it becomes available. If the environment was cloned, confirm and re-save the reference first. ### Sat, Map, 3D The switch at the top right of the viewer picks the view: | | What you get | Use it for | | ------- | ------------------------------------------- | ------------------------------------------------------------- | | **Sat** | Satellite imagery, straight down | Checking your scene against what is actually on the ground. | | **Map** | Road map, straight down | A clean site plan — roads and names, no photographic clutter. | | **3D** | Road map tilted, with Google's 3D buildings | Judging height and getting a feel for the site. | The scene tilts with the map, so in 3D your twins stand up on the ground next to real buildings instead of reading as marks on a floor plan. **3D uses the road map, not satellite** — and switching to it changes the imagery for you. Buildings are geometry in Google's drawn map; satellite is photography, so tilting it gives you the same photo at an angle rather than a city you can see the height of. Both flat views are the honest ones for placing and checking a point: straight down, one screen pixel to one spot on the ground. Coming back to **3D** returns to the tilt you last had, so flattening to check something does not throw away a view you set up by hand. **View → Top** and **View → Isometric** move between flat and tilted too. The compass, rotate and pitch buttons underneath handle orientation. While the map is flat, dragging cannot tilt it — press **3D** or a pitch button to leave the plan view, so an accidental drag never quietly angles a view you are picking points in. Each of those buttons works two ways. A click steps: 30° of rotation, 15° of pitch. **Holding** the button — or holding its keys — turns the map continuously until you let go, which is how you line the view up with something rather than counting presses. A hold starts slow and eases up to full speed over about half a second, so a tap nudges and a hold sweeps. | Keys | Does | | ------------------------ | -------------------------------------------- | | `Ctrl`+`Shift`+`←` / `→` | Rotate anticlockwise / clockwise | | `Ctrl`+`Shift`+`↑` / `↓` | Pitch towards the horizon / towards top-down | Letting go of either modifier stops the movement, as does releasing the arrow. The keys stand down while a robot is under keyboard control, so a keypress never both drives a robot and moves the camera. The buttons keep working either way. Google's imagery runs out before the view does: satellite stops at about 5 cm per screen pixel, the road map one level closer, and a robot tens of centimetres across is only a few pixels there. So zoom carries on past that point — twins, waypoints and areas keep being redrawn sharp while the imagery beneath them is enlarged and goes soft, up to 16× closer than Google's own limit. The **microscope** button at the bottom of the control cluster switches that on and off, and shows how far past the limit you currently are. Turn it off when the imagery is what you are looking at — lining the environment up against a building edge, or taking a screenshot — and the view stops where Google's sharp imagery stops. Leave it on to inspect a twin. How much 3D you get is Google's data, not a setting: buildings show up in covered areas at close zoom, and a rural site may stay flat however far you tilt. Google also limits the tilt as you zoom out, so zoom in before judging it. The map is a visual aid, not a survey. It is accurate to roughly the same degree as the geo reference itself, and satellite imagery of tall buildings leans a little even looking straight down. ## Type a position as latitude and longitude Anything you can place — a twin, a waypoint, an area, a shape — has an **XYZ / GPS** switch on its Transform section once the environment has a geo reference. **GPS** swaps the position fields for **Lat**, **Lon** and **Alt**, so you can type a coordinate off a site plan or a survey instead of working out how many metres east of the origin it is. It is the same position either way: the scene still stores metres from the origin, and the switch only changes how you read and type it. Turning it on and off does not move anything. The fields open on **GPS** while the map is showing and on **XYZ** otherwise, which is usually what you want — once you pick one, it stays picked. Altitude is absolute, in the datum your geo reference is set to, not height above the floor. The line under the fields says which. A value is applied when you leave the field or press Enter, not as you type — every part of a coordinate is a valid coordinate somewhere else, and `4` on the way to `48.1496` is several kilometres away. Twins docked to another twin, and waypoints placed relative to something else, keep metre fields only. Their position is an offset from whatever they are attached to rather than a spot on Earth, so there is no coordinate to show. ## Position a twin from GPS Select the twin, then in the twin editor turn on **Position from GPS**. It is off by default, and it requires two things: 1. The environment has a geo reference. 2. The twin declares a `gps` sensor — a GNSS receiver it actually has. Options: | Option | Use it when | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Heading** | Turn the twin to the fix's compass heading, or leave heading to whatever the device reports separately. | | **Altitude** | Take height from GNSS (aircraft), or pin the twin to the reference plane (ground vehicles, where GNSS height is mostly noise). Pin to the plane if your device does not report altitude — fixes without one are rejected rather than treated as zero, which would put the twin underground. | | **Minimum fix / Max error** | Reject fixes below this quality. Devices that do not report quality or accuracy at all are accepted regardless. | Once on, the twin's own position telemetry is ignored in Live mode — GPS is the single source of truth for where it is. Changing the twin's options takes effect straight away too. Those two requirements hold for as long as GPS positioning is on, so while it is on you cannot swap the twin to an asset without a `gps` sensor, remove the sensor from its schema, or sync it with an asset that has none. Turn **Position from GPS** off first. The alternative would be a twin that quietly stops appearing in Live mode some time later, with nothing to connect it to the edit that caused it. ## When the twin does not appear A GPS-positioned twin with no usable position is **hidden**, not drawn at its saved spot, because that spot is not georeferenced and showing it would be misleading. An alert card explains which case it is. Some of these degrade the twin rather than hiding it — the card says which: | Card | What to do | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **No geo reference** | Set it in Edit mode. | | **Geo reference needs confirming** | The environment was cloned; re-confirm the values. | | **No GNSS fix** | Nothing is arriving. Check the device is online and publishing. | | **GNSS fix is stale** | The stream stopped. The twin freezes at its last known position and the card shows the age. | | **GNSS fix not usable** | Below your quality threshold, an unrecognized fix type, or no altitude while height comes from GNSS — the card names the reason. | | **GNSS fix carries no heading** | The device sent no compass heading. The twin is still placed correctly; only its facing comes from elsewhere. Set heading to "leave to the device" to silence this. | | **GNSS fix far from geo reference** | The fix is kilometres away. Either the reference or the device is wrong. | The twin editor also shows a live readout — latitude, longitude, fix type, satellites and the resulting scene position — which is the quickest way to tell whether a twin is being placed by GPS or by something else. ## Accuracy Placement is as accurate as the fix. Consumer GNSS is typically 1.5–5 m; RTK is centimetres. The coordinate conversion itself contributes a couple of centimetres at a few hundred metres from the reference, so it is never the limiting factor. Heading is read as degrees from **true** north. If a device reports magnetic north without correcting for declination, its heading will be consistently off by the local declination angle. # Environment editor Source: https://docs.cyberwave.com/feature-reference/environment-editor/index Create and customize 3D environments for your robotics simulations and testing scenarios ## What is the environment editor? The environment editor is a 3D design tool for setting up digital twins and static objects in an environment. You can arrange robots, cameras, sensors, areas, waypoints, and scene geometry before using them in simulation or workflows. Robot, sensors, objects, and whole facilities One click export to MuJoCo. Simulate camera streams and sensor data. Stream real data from your cameras and robots, visualize them in the environment *** ## Key Features The Environment Editor provides a comprehensive set of tools for creating and managing your simulation environments. Intuitive visual editor with snap-to-grid functionality Work with your team in real time Exact coordinate control for professional layouts Top-down, perspective, and orthographic views Undo/redo and environment versioning Real-time physics simulation while editing *** ## Working across tabs and with teammates In **Simulate** and **Live**, choose **Monitor** or **Control** directly beneath the main mode buttons. Open the workbench’s **Activity** tab to follow workflow runs and their steps without sending commands. File, Edit, View, and other tools appear directly on wider screens and move into **Menu** on compact screens. Mode labels and workbench shortcuts stay visible on wider screens. Below 1024px, the side panels start closed; choose **Panels → Scene tree** or **Inspector** to open one at a time. Widening the window restores your desktop layout. Compact screens move **Share**, **Environment settings**, and **Order hardware** into **Menu → File**. Double-click a side-panel divider or the workbench's top divider to hide that panel; reopen it from the matching left, right, or bottom panel button (or **Panels** on compact screens). Dragging the same divider still resizes it. Click the scene search prompt anywhere to search scene objects and the catalog, including in Simulate or Live. Adding results to the scene still requires Edit mode and permission. Hover a disabled add action to see whether to switch to Edit or request permission. Other compact search controls open from their search icon; **Escape** collapses it without clearing the query; the visible query chip reopens it, and **Clear search** removes the filter. The clear X appears only with text; the scene’s + remains available while searching. Wider workflow panels show short status labels beside their icons. Scene rows keep a stable height, with secondary details on hover or focus and hidden, locked, or failed states kept visible. The **Environment assistant** keeps its conversation when you switch between **Edit** and **Monitor** in Simulation or Live within the same page session. Small labels show where each request happened; replies keep their original label even if you switch views while waiting. Earlier messages remain visible. The selected right-hand tab stays open across mode switches. Select a scene object to inspect it, or open **Agent** to return to the conversation. Returning to **Edit** restores the selected twin’s editable details without another click. If **Agent** is open, it stays open. Unsent environment assistant drafts, tagged objects and reference images stay available when you visit Control and return. Restoring a draft never sends it; the control agent still has a separate composer. Monitor keeps action cards read-only. Switching to Monitor requests a stop to unfinished assistant editing, but does not stop running robots or training jobs. Conversation history is not yet restored across page reloads or separate browser tabs. **Replay** appears when saved simulation runs or recorded streams are available. It stays reachable while availability is loading or unknown, and remains visible while Replay is the selected mode. Empty environments hide it after the availability check; new recordings restore it automatically. **Simulate** shows no dot without a running or initializing simulation, and a green dot when the simulation is ready. Enabling Playground physics alone does not mark a simulation as running. **Live** shows no dot without paired hardware, a gray dot for paired hardware that is disconnected, and a blue dot while hardware is connected. While simulation provisions or loads its physics scene, a spinner replaces its dot and reports **Simulation booting**, even if Playground physics is also enabled. A chevron on the selected mode indicates its status card; click to open it, or hover to preview it. With the mode selected, **Enter** opens and focuses its controls; **Escape** returns focus to the mode button. Without paired hardware, the Live card shows onboarding instead of an empty Edges status. Switch to **Edit**, choose **Add from Catalog** to add a robot or sensor, pair it with an edge device, then return to **Live**. **Ask assistant how to connect** opens the assistant and sends a setup question covering these steps. Boot indicators keep spinning while the status card is open. Idle recording controls are hidden by default. An active recording keeps **Recording · Stop & save** visible across modes, even when recording controls are hidden. In Simulate, choose **View → Show recording** to show or hide a separate recording bar on the right. It moves below the mode toolbar when space is limited, keeping the modes centered and unobstructed. Mode labels collapse to accessible icons when the space between the side panels is limited, and return when there is room. Click inside the card to keep it open while choosing an engine or adjusting settings; click outside or press Escape to close it. The people icon beside the mode buttons shows open sessions, including your own other tabs. Hover or focus it to see who is editing, viewing, or using Simulation, Live, or Replay. Closed sessions disappear after a short timeout if they cannot disconnect cleanly. Saved scene-order and group changes update other connected editors. Opening a mode does not lock the scene. If two people change the same hierarchy concurrently, the editor restores the latest saved version instead of silently overwriting someone else's work. In a narrow workflow workbench, **Switch** opens the workflow list and **Show node library** opens the node picker. Both leave room for the canvas and restore the full sidebars when there is enough space. ## Adding Primitives Moving or rotating a primitive keeps its template dimensions unchanged. Use **Scale** or the **Template** fields to resize it. ### Procedural walls and staircases Select a procedural object to edit its **Template** section in the right inspector. Numeric values commit when you press Enter or leave the field, so you can type a complete decimal without resizing the scene at each keystroke. **Apply a layout preset** provides starting configurations from the catalog. * **Wall Loop:** set room width/depth, wall height and thickness. Width/depth measure between wall centerlines; clear interior dimensions subtract one wall thickness. Flush corners preserve the existing outer footprint. Choose an **Open side** for a three-sided alcove, or a **Doorway side**, clear width/height and signed offset for a real opening in both rendering and physics. A doorway must fit between the corners and below the wall top, and cannot occupy the omitted side. * **Wall Path:** edit numbered X/Y points in meters, inspect the footprint preview, then click **Apply footprint**. Enable **Close loop** for irregular rooms, or leave it off for L/U-shaped partitions. Right-angle joints are flush; angled joints use simple overlapping boxes, not CAD miters. Paths support up to 64 points. * **Staircase:** choose a step count, riser height, tread depth, width and optional top landing. Examples include low training steps, indoor stairs and broad outdoor steps. Stairs ascend local +X; rotate the object to change direction. The terrain remains fixed in MuJoCo, with matching visible and collision steps. Parameter edits preserve the ground anchor. Use position/rotation to place these structures; use their parameters to change dimensions. Terrain creation alone does not train or validate a robot policy. ### Catalog primitives The **Add** menu (or the **+** button in the editor toolbar) includes a **Primitives** section. Primitives are curated public catalog assets with a short alias — things like cameras, lidars, and common generic objects — that you can drop into any environment in one click. * **Where to find them:** open the 3D editor, click **Add → Primitives** (or the catalog icon in the sidebar) to browse the full list. * **Why use them:** primitives are the fastest way to populate an environment. Because each primitive carries a short alias (e.g. `camera`, `lidar`), you can also instantiate them programmatically without knowing the full `vendor/slug` registry ID: ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() # Browse available primitives and their aliases for p in cw.assets.list_primitives(): print(p.registry_id_alias, "->", p.registry_id) # Instantiate by alias — no catalog search needed camera = cw.twin("camera") lidar = cw.twin("lidar") ``` *** ## Deleting scene objects Delete the selected object with **Delete** or **Backspace**, from the trash button in the right inspector, from **More actions → Delete** in the scene list, or by right-clicking it in the 3D view. Selecting several objects and pressing **Delete** removes them together after one confirmation. **Ctrl/Cmd + Z** undoes the last delete in the same page session; a reload clears the history. Deleting a procedural object is undoable from every entry point — the shortcut, the inspector's trash button, the scene list and the right-click menu — as is any multi-object delete. Restored twins and procedural objects come back as new objects, so they do not return to the group they were in; restored areas and waypoints do. *** ## Edge Core connection status (Live mode) When you are in **Live** mode, the right-hand panel shows an Edge Core status indicator: * **Green dot**: expected Edge Core instances are currently connected. * **Gray dot**: one or more expected Edge Core instances are not currently connected. Hover the dot to see: * how many Edge Core instances are currently connected, and * how many are expected for the environment. Expected cores are derived from the unique edge fingerprints configured on twins in that environment. *** ## Twin presence indicator (Live mode) In **Live** mode, every twin that has been paired to an edge device renders a small status dot overlaid on its kind icon. The dot consumes the same `edge_health` heartbeat that powers the Edge Devices status panel. ### States | Color | Meaning | | ------ | ----------------------------------------------------------------- | | Green | Connected — heartbeat fresh and all streams healthy | | Yellow | Degraded — heartbeat fresh but at least one stream unhealthy | | Red | Disconnected — no recent heartbeat (tooltip shows last-seen age) | | Gray | Checking — waiting for the first heartbeat after the panel mounts | ### Where you see it * **Twin editor panel** (top-right, next to the twin name): a slightly larger dot for the focused twin. * **Scene objects panel** (left list, on each twin row): a small corner dot on the kind icon. The dot is hidden in Editor and Simulate modes, on splat twins, and on twins that have never been paired to an edge device — there is nothing to present for those. Hover (or focus via keyboard) the dot for the tooltip: `Connected`, `Degraded — 1/2 streams healthy`, `Disconnected — last seen 12s ago`, or `Checking edge connection...`. *** ## Center the view on a twin **Double-click a twin's row** in the scene objects panel to bring it into the middle of the view. * **Single-click still just selects.** The camera only moves on a double-click, so you can click down a list of twins to read their properties without the viewport jumping around. * **Your zoom is kept.** The view slides over to the twin at the distance and angle you were already working at, rather than zooming to fit it. Use **View → Center** when you do want the camera refitted. * **Map mode pans the map** to the twin's location instead, at the current zoom. * Double-clicking a twin's **name** still renames it — double-click anywhere else on the row to center. Available to anyone who can see the environment, including read-only viewers. *** ## Twin joint edits in edit mode In **Edit** mode, changing a twin joint updates the scene immediately, publishes the edit over MQTT for local feedback, and persists the joint pose on the twin so it survives refresh and reload. *** ## Twin position quick actions In the environment editor transform panel, **Center** moves the selected twin or procedural object to the world origin. **Below**, **Above**, **Left**, and **Right** ask the Environment Editor to place it relative to the nearest suitable object or support using `cw_transform_environment_object`; floor/support placement uses `snap_to_support=true`. *** ## Semantic properties and route policy Areas, procedural primitives, and twins can carry semantic properties on their environment instance. Editing them does not change the source catalog asset. * **Description for agents** adds bounded scene context. It helps assistants understand intent but is not a deterministic safety rule. * **Semantic tags** add structured meaning. `access:no-go` or `access:restricted` on an area or primitive makes its geometry a planning obstacle. * Add one or more `asset:vendor/model` tags to scope that access policy to matching assets. Without an `asset:*` tag, it applies to every asset. * Semantic tags on a twin are descriptive. Put spatial access policy on an area or primitive so the planner has geometry to constrain. The editor preserves an unsaved draft if the API rejects a save and offers an explicit retry. The Environment Agent and MCP tools update the same `metadata.semantic_description` and `metadata.semantic_tags` fields with revision checks, so natural-language and manual edits remain consistent. See [Inspect areas with Move Twin](/feature-reference/workflows/inspect-area) for examples, planner behavior, sensor FOV, and runtime safety boundaries. *** ## Twin override export controls In the twin editor, **Twin overrides** lets you set per-twin appearance color, opacity, fixed-base behavior, and a total exported MuJoCo mass in kilograms. Cyberwave converts the total mass into proportional per-link scaling during MuJoCo export, and the editor shows an **Export warning** badge when the asset snapshot has incomplete inertial data that makes the export best-effort. *** ## Reorder root twins in Scene Objects In **Edit** mode, the Scene Objects left pane supports drag-and-drop reordering for root twins using a grip handle. Child twins stay attached to their parent group and move with the parent when reordered. * Reordering is available only when edit controls are enabled and search is not active. * Order is saved to environment settings as `twin_order`, so it persists across reloads. * Live stream cards in the right pane now follow the same persisted twin order. *** ## Simulate tab playground physics In **Simulate → Playground**, Cyberwave now applies lightweight frontend physics with gravity and basic rigid collisions. URDF twins use their `` geometry as collision sources when available, and a fallback collider is used when collision metadata is missing. *** ## Start the agent from the Edit menu In the 3D editor, open **Edit → Editor Agent** to launch the Environment Agent. It can inspect the current environment and call Cyberwave MCP tools for supported edits. * The agent automatically provisions a workspace-scoped API key for the session so you can start chatting immediately. * The agent displays a **Used tools** line for each response so you can verify which MCP tools were invoked. *** ## Workflow executions in an environment In the environment editor, open **Executions → Workflow Executions** to review recent workflow runs bound to the current environment. * The list stays compact by default and shows workflow name, status, and run time. * Select a run to inspect trigger data, errors, and metadata. * **Node Executions** stay collapsed behind **Show more** so the default view stays lightweight. *** ## Sensor coverage previews In **Edit** and **Live** modes, the viewer draws each sensor's coverage envelope, matched to how that sensor actually sees the world: | Sensor | Preview | | ------------------------- | ----------------------------------------------------------------------------------------------- | | RGB / depth cameras | Pinhole frustum from the camera's field of view and image aspect ratio | | 2D lidar / laser scanners | Flat scan fan across the horizontal sweep | | 3D / 4D lidar | Swept volume rounded at the sensor's full range, bounded above and below by its vertical spread | | Radar | Cone | Ranged sensors take their reach from `max_range`, and sweeps up to a full 360° are supported. A lidar with less than 180° of vertical spread does not cover straight up or straight down, so its envelope is closed off at the top and bottom rather than drawn as a full sphere. Sensors with no spatial coverage — IMU, GPS, compass, microphones — draw nothing. Each preview uses its sensor type's color; RGB and depth cameras are colored differently so overlapping cones on the same mount stay distinguishable. Very long ranges are shortened so they don't swamp the scene. When that happens, the twin's sensor settings show **Preview extent** with both the drawn distance and the sensor's full range, so you can tell a truncated preview from a short-range sensor. Set a preview length override on the sensor to draw its full reach. Control them from **View → Show sensor previews**, then **Sensor preview types** to toggle camera frustums, laser scan fans, lidar sweep volumes, and radar cones independently. The same submenu has **Only the selected twin**, which limits previews to the twin you have selected — deselect to see every twin's previews again. Per-sensor color and preview length can be overridden in the twin's sensor settings. *** ## Live point cloud alignment In **Live** mode, depth-camera point clouds now keep the viewer's existing camera-local basis (`X` lateral, `Z` depth) while still honoring the sensor pose and offset, so RealSense clouds stay vertically aligned in front of the sensor after refresh and axis migrations. *** ## Clone an environment Use **File → Make a copy** to duplicate the current environment. * The copy includes the environment and all of its twins. * The copy is created in the same workspace and project as the original, regardless of which workspace you were last browsing. * If the environment was shared with you and you are not a member of its workspace, the copy is created in your own workspace instead, outside any project. * Historical telemetry/session data is not copied. * Lineage references are stored in metadata for future tracking: * environment settings include `cloned_from_environment_uuid` * each twin metadata includes `cloned_from_twin_uuid` *** ## Ready to Build? Start creating immersive environments for your robots and unlock the full potential of simulation-based development. Start building your environment now Control environments programmatically Learn about digital twins Control physical robots in real time from the environment Automate robot operations with visual workflows # Waypoints on the map Source: https://docs.cyberwave.com/feature-reference/environment-editor/map-waypoints Drop route stops onto the satellite map, including while a simulation or live session is running. ## What this is for A **waypoint** is a named stop on a route. A mission built with the **Move Twin** node walks them in order. Waypoints can be placed directly on the georeferenced satellite map, and unlike the rest of the scene they can be placed in **Simulate** and **Live** as well as **Edit**. So you can watch a run, see somewhere the robot should also visit, and add it without leaving the session. Placing waypoints works with or without a map. To place them *on the satellite map* you need a [geo reference](/feature-reference/environment-editor/geo-reference) and the basemap turned on — without a geo reference the environment has no place on Earth, so there is no map to show. Right-clicking the ground in the 3D scene works either way. ## Add a waypoint 1. Turn on the basemap from the header (optional — see above). 2. Right-click the ground where you want the stop. 3. Choose **Add waypoint**. The new waypoint opens in the right panel, where you can rename it, group it into a collection, and adjust its position. When the environment has a geo reference the panel also shows the waypoint's latitude and longitude underneath the position fields. Drag an existing waypoint's gizmo to move it. This works in Simulate and Live too. ## While a mission is running **Waypoints are locked for the duration of a run.** Adding, deleting or dragging one is unavailable while a workflow is walking the route, and the disabled **Add waypoint** entry names the run that is holding it. This is deliberate. A route that changed mid-mission would send the robot somewhere you never approved, and the run's arrival records would refer to stops that no longer exist. Wait for the run to finish, or cancel it, then edit. Renaming a workflow's waypoints is not the same as changing the route — the mission holds waypoint identities, so a rename is safe once the run ends. ## Collect data along a route On a **Move Twin** node: | Option | What you get | | ----------------------- | ----------------------------------------------------- | | Take picture on arrival | One image per waypoint, attached to the run | | Pause seconds | Dwell time at each stop before the workflow continues | | Per-waypoint duration | How long the move to each stop should take | Bracket the mission with **Recorder** nodes to capture audio or video for the whole run. Captures and recordings appear on the run in the workflow execution detail. Each waypoint the robot reaches is also logged, so you can see the route it actually walked in the environment's **Events** tab. # Point cloud import Source: https://docs.cyberwave.com/feature-reference/environment-editor/point-cloud-import Import LAS, LAZ, and PLY scans into the catalog or an environment. Import **LAS**, **LAZ**, or point-only **PLY** scans. Cyberwave reports the point count, bounds, colour depth, and available CRS text, then prepares the cloud for the 3D viewer. ## Uploading Use **Upload asset** to add a reusable catalog scan, or **Import scan or splat** inside an environment to place it there. Direct uploads support files up to 32 MB; larger files upload through the attachment flow and may continue processing in the background. LAS, LAZ, and PLY scans all get the same normalization and measured point radius. A PLY that contains Gaussian splat data is recognised and kept as a splat, so uploading one never flattens it. ## Alignment Scans are interpreted as metres and Z-up when their metadata does not say otherwise. Set units or choose Y-up when needed. Large georeferenced scans are recentred automatically and retain their offset in the import report. An imported scan is not automatically aligned with an environment unless it came from a Cyberwave environment export. Use the normal scene transform controls to register it before using it for environment-frame work. # Replay recordings Source: https://docs.cyberwave.com/feature-reference/environment-editor/replay Save simulation runs and replay motion, sensor media, and execution evidence. Recording playback loads **signed URLs** from the API instead of inlined samples: * **Camera**: MP4 (and legacy MKV chunk lists) via signed URL; the browser uses HTTP range requests as needed. * **Audio**: MP3 via signed URL; plays back in sync with the timeline. * **Robot / actuation**: Parquet via signed URL; the web app reads a **time window** of rows around the playhead (bounded memory). * **Point clouds**: FlatBuffer chunk URLs plus coarse timestamp indexes from metadata. The `GET /api/v1/environments/{uuid}/recordings/{recording_uuid}/data` endpoint returns compact **source descriptors** (URLs + bounds + column hints), not dense per-frame JSON. ## Save a simulation run Start a backend simulation, then select **Record** in the top-right of the 3D view. **Stop & save** adds the run to **Replay** and provides a **View recording** link. The run groups recorded motion, available sensor media, linked workflow executions, and their evidence. Missing or unfinished streams are identified in the run details. Sound-emission indicators replay at their recorded timestamps. Scene labels are off by default. Hover an object or its scene-tree row to reveal its name, or enable labels from **View** or the labels toolbar button. Agent overview previews include labels by default. Sensor imagery excludes editor labels. In **Replay**, the left sidebar lists recent saved runs with a compact **Play** icon to open a run and a **⋯** menu for **Execution & evidence**. Use the Replays and Scene items icons to switch lists; select the active icon again to collapse the sidebar. Long names stay compact and reveal their full text on hover. **Advanced: choose streams** opens the date and stream picker for manual combinations. Use **Play / Pause** beside the speed controls. The chevron at the right of the timeline minimizes its rows while keeping playback controls available. Select it again to expand. Fullscreen hides the workbench bar. For a local environment without robot driver images, select **Physics only** under Simulation → Advanced settings → Robot runtime, and enable assigned controllers when needed. The default Auto runtime continues to use the robot's drivers. ## Open a saved run Select a run's name to load it without playing. Its **Play** icon starts playback. **Preparing Replay** stays visible with a spinner while the run is saving and its motion and sensor streams are loading. A saved-run URL includes `?mode=replay&run=` and reopens that run for users who have access to the environment. ## Playback timing A recording can retain both the wall-clock time each sample arrived and the producer's own clock. **Source clock** is the default when the second is available: robot motion, camera media, audio, and events follow that one timeline, so a slow simulation step or an acquisition pause does not stretch the mission's playback duration. Choose **Wall clock** in timeline settings to inspect those pauses. Recordings without source-clock anchors use wall timing. Playback can briefly wait for required media to load. ## Export an MP4 In **Replay**, select **Export MP4** in the playback toolbar beneath the 3D view. Choose the start and end time, then select **Download MP4**. The export uses the current camera angle and playback timing, rendering the 3D scene at a fixed **1280 × 720, 30 fps**. Rendering may take longer than the resulting video; rendering delays are not included in the file. Progress and cancellation are available in the dialog. Use Chrome or Edge with video encoding support. Each export can contain up to two minutes. The MP4 contains the 3D scene without audio; camera videos, microphone recordings, and execution evidence remain accessible in Replay. The file metadata includes a link back to the run, subject to the environment's normal access rules. # Replay timeline & recordings Source: https://docs.cyberwave.com/feature-reference/environment-editor/replay-timeline Reading the replay timeline, the color legend, and slicing recordings into episodes. The **Replay** timeline shows everything an [environment](/feature-reference/environment-editor/index) recorded over a time window, laid out left-to-right. Each kind of data gets its own labeled row, filled bars show where that data exists, and dots in the **Events** row mark things that happened. ## Open replay over a recording 1. Switch the environment to **Replay**. 2. Click the **calendar** button. 3. Pick the date (the day you recorded, or **May 8, 2026** if you're using the suggested demo environment). 4. **Load sessions**, no filters needed and the timeline fills in. The recordings list has its own filters in its header — **twin**, **data source** (live or simulation) and **replay stream** (robot, camera, audio, depth, point cloud). Each is a dropdown you can tick several values in; everything is included until you untick something, and **Clear filters** puts it back. ## Camera & audio sidebar The right-hand **Camera & audio** tab plays media available at the Replay cursor. Robot motion plays in the **3D scene and timeline**, not in this tab. A motion-only recording can therefore replay without camera or audio tracks. If media exists elsewhere in the recording, move the cursor onto its timeline clip to view or hear it. ## Rows One row per kind of data, labeled on the left. A row only appears when there is something in it: | Row | What it holds | | ----------- | ------------------------------------ | | Robot | Joint states and actuation telemetry | | Video | Recorded camera streams | | Depth | Depth / LiDAR frames, geometry only | | Point cloud | Depth frames fused with camera color | | Audio | Recorded audio samples | | Events | Alerts, workflow steps and telemetry | | Episodes | Segments you labeled yourself | When two sources of the same kind overlap in time — two cameras recording the same minute — their bars stack inside the row so you can see both. The row gets taller; the bars stay the same thickness, so a bar never looks different just because something overlaps it. If more overlap than fit, the row label shows a **+N**, and hovering still lists every one of them. **Episodes stack the same way.** Two episodes covering the same stretch, or one nested inside another, each get their own line in the Episodes row, so you can hover and click either. Each line down the stack is a shade deeper green, so you can follow one episode from start to end even where others cross it. When more episodes overlap than there are lines, the ones sharing a line are drawn with a diagonal hatch — they cover each other, so hover any of them to list what is actually there. ## Color legend Open the **Legend** popover in the toolbar at any time. There are only three things a color can mean here: | Color | Meaning | | --------------- | ----------------------------------------------------------- | | 🔵 Cyan bar | A **recording** — the row label on the left says which kind | | 🟢 Green span | An **episode** — a labeled segment you created | | 🟢 Deeper green | How deep in the overlap stack that episode sits | | Hatched green | Episodes sharing one line, so they cover each other | | Dot | An **event** — colored by severity, see below | Every recording bar is the same cyan, whatever kind of data it holds. The row label tells you the kind, so the color doesn't need to repeat it — and it means you never have to tell two similar shades apart. Event dots use a separate scale, so an event can never be mistaken for a recording: | Dot | Meaning | | --------- | ------------------------------------------------------ | | ⚪ Gray | Info — informational alerts, workflow steps, telemetry | | 🟠 Orange | Warning | | 🔴 Red | Error or critical | A **solid** dot is an alert; a **hollow** one is a workflow step or telemetry. When several events land too close together to draw apart they merge into one wider dot carrying their count — hover to see each of them individually. ## Hover to see what's there Hover any row and a card appears next to the cursor. **Hover a recording bar** and it tells you whose recording it is — the kind of data, the twin's name, and the twin's UUID (click to copy). That's it: the bar's position and width already show you when it starts and how long it runs. When several sources overlap, each one gets its own stacked bar in the row, so you hover the specific bar you're interested in and get that source — not a list of everything sharing the row. On a keyboard, **←** / **→** move along one source and **↑** / **↓** switch between the stacked ones. **Hover the Events row** and you get the events at that moment instead, in the order you need them: the **twin** (name, plus its UUID to copy), the **severity** spelled out — Info, Warning or Critical — then the event's name and its message. The timestamp sits in the card's header. Each row only ever tells you about its own contents, so a card never mixes recordings and events. If nothing is there, the card says so rather than going blank. **Click an Events dot to pin its card open.** A hover card disappears as soon as you move away, which makes the UUIDs on it hard to click; a pinned one stays until you click elsewhere or press **Esc**, and says so. Clicking still moves the playhead to the event as well. Keyboard works the same way: **Tab** to a row, **←** / **→** to step between recording edges, **Home** / **End** for the first and last, **Enter** to move the playhead there — and in the Events row, **Enter** also pins the card. ## What you can do here The row above the timeline holds what you reach for while watching — playback speed, play/pause, Create Episode, the calendar. Everything that changes how the timeline *reads* sits under the **Settings** gear beside the Legend: time reference, 3D rendered mode, and the Events filter. A setting only appears there when there is something to choose. * **Scrub & play back** at 1× or 2×; click anywhere on a row to jump there. * **Zoom** into a stretch of the timeline for frame-level detail. * **Filter the Events row** by twin with **Settings → Events for**. Recording rows are unaffected. * **Pick the 3D rendered mode** — **Depth** or **Point cloud** — under **Settings**, when a recording holds both. It chooses which one the 3D view draws, and emphasizes the matching row. * **Browse sessions** by date with the calendar picker. * **Create an episode** — mark a window and label it as a [training/dataset](/feature-reference/datasets/import) segment. Hit **Create Episode** and a short panel opens next to the button telling you which point it wants next; then click the timeline twice. The playhead jumps to each click and turns green once the first mark lands, the two marks are ruled across every row, and the range between them fills in green with its duration before the naming dialog opens. **M** at the playhead does the same from the keyboard, and **Esc** leaves the mode. ## Why it matters * **Research:** turn real runs into labeled [episodes and datasets](/overview/features/replay-and-historical-data) for training [VLAs](/feature-reference/ml-models/smolvla-training). * **Security & review:** re-watch exactly what a robot did, find the moment something went wrong, and inspect it frame-by-frame. See [Recording replay (signed URLs)](/feature-reference/environment-editor/replay) for how playback data loads, and [Replay & Historical Data](/overview/features/replay-and-historical-data) for the full pipeline. # Simulation timing and advanced settings Source: https://docs.cyberwave.com/feature-reference/environment-editor/simulation-timing Tune how fast a simulation steps, how often it publishes, and how its range sensors behave. The Sim tab's **Advanced Settings** section sets how a simulation runs. Every field is optional — leave one empty and the server picks, using the value shown in the box. If your environment has an RL controller assigned, the blanks are filled with the values that policy was trained at. ## The fields * **Physics timestep (dt)** — how far the simulator advances per step, in seconds. Smaller is more accurate and proportionally more expensive. Match your training dt if you care about matching a policy's behaviour. * **Pacing** — whether one second of simulated time takes one second of real time. Leave on *Auto* unless you know you want otherwise; navigation and mapping stacks plan against the clock and need real time. *Custom multiplier* lets a headless run go faster than real time. * **Stream frequency (Hz)** — how often the simulation publishes robot state and camera frames to controllers. Keep it at or above your policy's control rate. * **Range sensor rate (Hz)** — how often simulated LiDAR, radar and pointcloud sensors scan. * **Range self-hit fallback** — what a beam does when the first thing it meets is the robot's own body, or something closer than the sensor's minimum range. **Off by default**: the beam reports no return, which is what a physical scanner does when its own chassis is in the way. Turn it on and the beam continues past the obstruction and reports whatever is behind it — useful if you specifically want the older behaviour, but those are returns a real robot never produces. ## If a simulation runs slow or stutters Lower the **range sensor rate** first. Simulated range sensors are usually the most expensive thing in a scene: every scan traces a ray for each beam, and a high-resolution lidar scanning at full rate can consume most of a simulation's budget on its own. Dropping it to a few Hz often restores smooth motion with no visible change to navigation. If that isn't enough, in rough order: 1. Check the **range self-hit fallback** is off. It is off by default, and on a robot whose scanner can see its own legs or wheels, resolving those beams costs far more than every other beam combined. 2. Raise the **physics timestep** — this is the cheapest large gain. Watch for robots jittering against the floor or sinking into it, which means you have gone too far. 3. Lower the **stream frequency**, as long as it stays at or above your controller's rate. 4. Reduce the sensor's own resolution on the asset (its points-per-second and update rate), which lowers the cost of every individual scan rather than the number of scans. Setting the range sensor rate to `0` removes the separate budget and scans on every stream pass — the older behaviour, and rarely what you want on a scene with a real lidar on it. ## When you can change them For a 3D range sensor, the saved sensor configuration can declare horizontal and vertical resolution and field of view. The simulator samples those rows within its total ray budget. A sensor with no vertical rows retains its existing planar scan. If the scan is empty, check its mounting position and orientation: a sensor inside the robot may only see the robot itself. A point cloud is an observation; it does not by itself establish a saved map or obstacle avoidance. These settings are fixed for the life of a run. Set them before pressing **Start**; the fields are disabled while a simulation is active. Values you type are kept even if you collapse the section. # Simulation view Source: https://docs.cyberwave.com/feature-reference/environment-editor/simulation-view See MuJoCo's own render of your scene, following the camera you are already moving. Editors enter **Simulate** and **Live** in **Controlling** by default. Choose **View → Monitoring** to watch without sending robot commands, then **Back to Controlling** to restore input. The choice is remembered per environment. Users without edit access remain in Monitoring and can select Simulate only while a simulation is active, or Live while hardware is connected. Editors can manage simulation while Monitoring without enabling robot commands. ## One assistant across views The environment assistant keeps the same conversation in Edit, Simulation and Live, with labels showing where each request happened. **Monitor** inspects; **Control** can plan robot actions or propose a new skill. **Review in Simulation/Live** opens the existing execution controls; a plan is not a command. Switching sources while Monitoring leaves their workloads running. Taking control of Live performs the controller handover; use explicit stop/cancel controls to stop a robot or training job. Scene and workflow changes belong in Edit; review a workflow's runtime target before running it. While a simulation is running, the right-hand panel shows a **Simulation view** tile alongside your robots' camera feeds. It is the simulator's own render of the scene — with its lighting, shadows, materials and contact geometry — rather than the 3D scene the browser draws. ## It follows your camera Orbit, pan or zoom the 3D viewport and the simulation view follows. There is nothing to aim separately: the tile shows the same viewpoint, rendered by the physics engine. A few things worth knowing: * **It lags slightly while you move.** The video is encoded and streamed, so it settles a moment after you stop moving. The 3D scene stays immediate. * **Everyone shares one camera.** If two people have the environment open, the view follows whoever moved last. * **It is never recorded.** Unlike a robot's camera, this view is not saved to your recordings — it exists only while someone is watching. ## When it appears The tile shows up automatically in the right panel's Simulation tab once a simulation is running, whether or not any robot carries a camera. Its stream is off by default; use the header button to enable it. The tile disappears when the simulation stops. ## Turning it off The button in the tile's header switches the view off and back on at any point during a run — no restart, and nothing to set up beforehand. While it is off, the right-hand panel is closed, or you switch to Agent, its camera updates stop and the simulator's viewport expires after its idle timeout. Robot-camera streams and an already-running simulation are independent of this preference. Your choice is remembered per environment. # Live teleoperation Source: https://docs.cyberwave.com/feature-reference/environment-editor/teleoperation Control physical robots in real time through their digital twins from anywhere in the world. ## What is Live Teleoperation? Live Teleoperation lets you control a physical robot in real time through its [digital twin](/feature-reference/digital-twins) in the Cyberwave dashboard. Operator inputs — keyboard, gamepad, or SDK commands — are sent to the robot via Cyberwave's low-latency MQTT and WebRTC infrastructure, while live video and telemetry stream back to the browser. Teleoperation requires a physical robot connected through [Cyberwave Edge](/feature-reference/edge/overview). The Edge Core bridges your hardware to the cloud in real time. *** ## How It Works Send commands from the dashboard UI, a keyboard/gamepad controller, or the [Python SDK](/overview/tools/python-sdk) using `cw.affect("live")`. Cyberwave routes commands through MQTT to the Edge Core running on the robot's host machine. The Edge Core translates commands into hardware-level actions and streams sensor data back. ```mermaid theme={null} flowchart LR A["Operator\nBrowser"] <-->|"MQTT / WebRTC\ncommands + video"| B["Cyberwave\nCloud"] B <-->|"Serial / USB\ndriver commands"| C["Robot\nHardware"] D[Edge Core] -->|MQTT| B ``` *** ## Supported Control Methods | Method | Description | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | **Keyboard controller** | Assign a keyboard controller to a twin in the dashboard — move joints or navigate with key bindings | | **Gamepad** | Use a USB or Bluetooth gamepad for more intuitive control of mobile robots and arms | | **Leader arm** | Teleoperate a follower arm using a physical leader arm (e.g. SO-101 leader/follower setup) | | **Python SDK** | Send commands programmatically with `cw.affect("live")` — see the [SDK docs](/overview/tools/python-sdk#affect-simulation-vs-live-environment) | *** ## Monitoring and Controlling Editors enter Live and Simulate in **Controlling** by default. Choose **View → Monitoring** to watch without sending robot commands; **Back to Controlling** in the mode toolbar restores input. This personal choice is remembered per environment. The right sidebar is labeled **Commands** while controlling; **Controllers** in the workbench remains the place to configure control inputs and services. Open simulation setup or hardware pairing from the active **Simulate** or **Live** button at the top. A setup shortcut beside unavailable controls opens this same menu. The Live menu always lists the environment’s hardware; selecting a twin shows its own status and pairing shortcut in the sidebar. Users without edit access remain in **Monitoring**. They can watch an active simulation or connected hardware and switch between them when both are available. Switching monitored sources does not start, stop, or reconfigure them. Editors can still start and stop simulation while Monitoring; keyboard, gamepad, leader, and control-agent commands remain disabled until they return to Controlling. *** ## Run a saved pose or movement In **Controlling**, open **+ Pin** and choose the twin's **Saved poses and movements**. The compact picker lists the poses and movements already saved for that twin, its asset, or its environment. An icon identifies a pose or movement; source labels appear only when names repeat. Select one to check it, then choose **Run**. Live execution still requires confirmation and a connected runtime. In **Edit**, select the twin, set its joints and save a pose, or create a movement from saved poses. The existing authoring tools remain available. Switch to **Simulate** or **Live**, then use **Commands → + Pin** to select the saved-motion input. Edit preview and snap controls are separate from runtime execution. A saved motion must target declared, independently controllable joints within their limits. An unsupported joint in any step blocks the whole sequence. If a driver declares that it cannot accept joint commands, the Live check explains that restriction; simulation uses its own command transport. Fix the indicated joint or driver configuration before retrying. Empty motion libraries are not listed in **+ Pin**. Monitoring keeps the control read-only. A stopped simulator leaves the selected motion visible and explains why **Run** is unavailable. Simulation reports that the command trajectory completed; verify measured joint feedback before treating that as successful robot motion. Both roles show the same **Executions** tab, with its **Runs** and **Gallery** views. Monitoring only withholds the controls that write: canceling a run and deleting captures. *** ## Create a map In **Live**, select a twin configured for mapping (for example, a configured Go2), then open **Mapping** in the right panel. **Autonomy and logic** identifies the service and its configured sensor inputs. Choose an available map type, optionally enter a name, and click **Start mapping**. Click **Stop mapping** to request that the robot save and upload the map. In **Simulate**, wait for the simulation to finish starting before mapping. The buttons show progress while a start or save request is pending. Saved maps appear in the collapsible **Maps** group in the left scene list. Select a map to see its preview and details in the right inspector. Use the eye button to show it over the environment, or the three-dot menu for its other actions. Docked twins remain in the robot's selection. **Monitor** lets you inspect maps; switch to **Control** with edit access to start or stop mapping. Older sensor-based setups retain their sensor selector. In **Simulate** or **Live**, pin a supported map to **Control** to keep its view beside your controls and cameras. This is separate from showing its layer in the scene. A robot marker requires a compatible map reference and current position; pinning does not select the robot's navigation map or start mapping. ## Organize the operator view In **Simulate** or **Live**, use **+ Pin** in **Control** to choose controls, sensors and maps. Select a twin to customize its own view, or a map to inspect it. **Deselect** returns to the environment's **Control** or **Monitor** panel. Open the layout-name menu and choose **Arrange** to reorder or unpin items, then **Save layout** to finish. Shared layouts require permission to edit the environment. **Monitor** keeps the same views read-only. ## Choose a navigation destination Choose **Place target** to place a point or expand the coordinate fields. **Go to point** appears once a point is set. **Stop navigation** appears while a navigation command is active. A stopped simulation or unpaired live robot must be made ready before commands can run. **Destination set** means the destination configuration is valid. The navigation service checks the route when you choose **Go to point**; this label does not mean that a path is available or the robot has arrived. Follow the execution status for the result. ## Keyboard (Driver) **Keyboard (Driver)** is the default keyboard controller for robots that ship a driver catalog. It does not hard-code a command list. Each twin shows the commands that twin actually declares (from the driver interface on that twin). Bind a key in the controller, then reuse the same saved controller on another twin of the same asset: only the **intersection** is usable — commands present in both the twin's catalog and the saved bindings. Extra bindings for commands this twin does not have are ignored; catalog commands with no binding stay unbound. That is intentional. Subclass [`BaseDriver`](/feature-reference/edge/drivers/base-driver-class) (or declare the same commands in `cw-driver.yml`), run the driver, and the keyboard UI follows the manifest. ### Commands vs joints | Surface | Default | Hold a key | Tap a key | | ------------ | ---------------------------- | ------------------------------------------------------------------------------------------------- | ------------------ | | **Commands** | One-shot | Repeats only if the driver marks the command `continuous` (at that command's `rate_hz`, or 10 Hz) | Always one payload | | **Joints** | Continuous stream while held | Keeps sending setpoint updates | One step | A command like **capture photo** / **take photo** must stay one-shot. Locomotion and velocity commands are usually continuous. The driver manifest is the source of truth — the dashboard does not guess. * **Rebind** a key by clicking its slot and pressing a new key — the previous owner of that key is replaced. * **Radians / degrees** is a per-panel toggle: the controller panel and the controller card each convert their own joint readout. ### Which controller a new twin gets Each twin gets its own assigned controller. New twins start from the asset default — for catalog robots that is usually the public **Keyboard (Driver)** template. When more than one keyboard controller matches that default: 1. A **Save as my copy** controller linked to the asset is chosen first (your bindings stay the default for new twins of that asset). 2. Other controllers in the same workspace. 3. The public template. Picking a controller in the UI (or a specific slug/uuid in the SDK) always wins over this default. The public template is never overwritten; copies are yours. ## Driving Several Robots at Once Assign the same keyboard controller to more than one robot and a single keypress drives all of them together. From an assigned controller, use **Assign this controller to other twins** to give it to the environment's other robots in one step. With the legacy input setup, every robot with a keyboard controller receives keyboard input — selecting one in the scene does not stop the others from being driven. Each robot resolves the key against its own controller, so a robot whose controller does not bind that key simply does nothing, and robots with different controllers can still respond to the same key. Each robot keeps its own commanded targets and its own panel, so two arms starting from different poses stay independent: they receive the same *step*, not the same absolute position. Pick the robot in the **Controllers** tab's twin list to read its panel; the others keep driving either way. ## Compose a keyboard by action In **Control**, use the same standard keyboard for Drive, Camera and Lights. Each action stores its own keys and command values. No new controller copy is needed. New twins adopt the asset's saved configuration; Workbench edits belong to that twin. In **Map keys**, choose **Add key** to use the same command with a different value: for example, G for Grip and R for Release, or separate light intensities. Gamepads offer **Add input**. Set the parameters for each input before saving; the overview and operating guide show the saved choices beside their keys. Changing or removing one input preserves the others. Leader mappings follow the same pattern: **Map joints** saves a mapping for the asset, and **Use as default** selects its reusable input. Existing twins keep their own mappings. Calibrate the physical leader on its twin before operating. Standard inputs are offered only for commands the robot exposes. If its setup changes, saved keys stay visible for review; **Needs robot setup** identifies the missing interface without deleting your mappings. In Workbench **Overview**, **Use saved mappings** checks and selects these keys for one twin in this browser. It keeps the existing policy assignment and does not start a policy or robot. Other keyboard presets in this browser are suspended. If the simulator is stopped or still starting, pressing a mapped key explains why the input is unavailable. The pinned guide highlights accepted keys, including joint and gripper controls; this feedback does not confirm the robot reached its target. Changing mode pauses the selection; use the button again to resume. **Use previous input setup** explicitly restores the legacy routing, including multi-twin control. Saved edits take effect on the next selection. A pinned guide shows the selected keys. Template changes, conflicting keys or an incompatible policy connection must be reviewed first. Device/runtime availability and physical ownership checks still apply; this browser selection is not an exclusive robot lease. ## Binding One Key to Several Joints A key can be bound to more than one joint. Press it and every joint bound to it steps together; release it and all of them stop. In the key-bindings editor, assigning a key that another joint already uses no longer replaces that binding — both are kept, and the row notes which other joints the key drives. This is for joints you want to move *independently but together*. Joints that are mechanically coupled (a gripper's mirrored fingers, for example) already follow their driver automatically and do not need their own binding. *** ## Where the Controller Panel Lives The keyboard controller panel lives in the **Controllers** tab of the bottom workbench, next to that twin's key bindings. Select a twin in the tab's list to read its panel, or click the twin's keyboard button in the control dock at the bottom of the 3D view to open the tab straight on that twin. Keys keep driving the robot whether or not the panel is open — including with the workbench collapsed and in fullscreen. The panel is a readout, not the input. *** ## Joint Targets Readout The keyboard controller panel shows, for each independently controllable joint: | Column | Meaning | | -------------------- | ------------------------------------------------------------ | | **target** | The position the controller last commanded | | **position** | The position the robot (or simulator) reports | | **Δ** | How far the joint still has to travel | | **vel** / **effort** | Measured velocity and effort, when the driver publishes them | It behaves the same in Simulation and Live mode. While you hold a key, the joint's current position and commanded target are also shown next to the key itself, as `position → target`. Each key press moves the target by one fixed step from the **previous target**, so repeated presses add up predictably even while the robot is still moving toward the last one. A gap in the **Δ** column simply means the robot has not arrived yet; it turns amber if the robot is falling far enough behind that further presses are being held until it catches up. A joint you have not driven yet shows no **target** at all, and driving one joint never gives the others a target: each key press commands only the joints it actually moves, and every other joint simply holds the last position it was commanded to. The joint currently under a held key is highlighted. Mimic and fixed joints are not listed — they have no target of their own. Rotational joints are shown in degrees, linear joints in metres. A dash means the robot does not report that channel, and a dimmed position means the reading is stale. If the connection to the robot drops, held keys are released and the commanded target is discarded rather than resumed. When the link comes back the target re-seeds from the position the robot actually reports, so the first press afterwards steps from where the arm really is. *** ## Shared Controller Templates Use the same input template for multiple robots. In Workbench, **Edit mapping** saves supported keyboard and leader-arm mappings for that twin without changing the shared template. Composed keyboard inputs reuse one template across separate actions such as Drive, Camera direction and Lighting. For a robot with joint control, open its joint action, add **Standard gamepad**, and choose a button or stick direction for each joint. Apply the mapping, then **Save**. Overview combines these mappings with the same gamepad’s other actions. In Workbench, select the device and hold its enable button to use it; release controls before enabling again. Leader-arm settings can be reviewed offline; connect the device to capture calibration. If a save reports that the configuration changed, reopen it before editing again. In Catalog and Workbench **Control**, Overview shows saved keys and leader-to-joint pairs. Open an action and choose **Configure inputs** to add an input or edit its mappings. In Monitor, **View input settings** opens the same setup read-only. Existing presets remain under **Other controls**; editing one does not connect a device or start movement. Selecting saved keyboard or gamepad mappings pauses and disconnects the leader for that twin in this browser. Its assignment and saved calibration remain. Return to the previous input setup and choose **Connect** to use the leader again. Changing mode or losing Control access also releases the leader connection. Older preset editors may still offer **Save as my copy**. This creates a separate reusable preset; it is not required for supported twin-local mapping edits. Custom presets remain supported. *** ## Switching Between Simulation and Live The same [environment](/feature-reference/environment-editor/index) supports both modes. In **Simulation** mode, your actions affect the digital twin only. Switch to **Live** mode to drive the physical robot. **From the dashboard:** use the mode toggle in the environment header. Use **Capabilities → Joint-target availability** to declare **Simulation and Live**, **Simulation only**, **Live only**, or **Not supported**. This also applies to joint-based end-effector and motion actions. Unsupported actions are omitted from Controllers and the action picker; their declaration remains in Capabilities. Simulation-only actions stay visible but disabled in Live with a clear explanation. A missing Live driver implementation disables Live separately; it does not remove Simulation support. Without an explicit restriction, both runtimes are allowed when the required structure, setup and runtime are ready. Edit keeps configuration available for supported actions. When a Live robot disconnects, its prepared control becomes disabled and explains how to reconnect. Entered targets remain. Reconnecting checks the target again; review and confirm the new Live plan before executing. Reconnection never runs the previous command automatically. **From the SDK:** ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave() robot = cw.twin("the-robot-studio/so101") cw.affect("playground") # free; "simulation" starts a billable MuJoCo run robot.joints.set("shoulder_pan", 45, degrees=True) # moves the digital twin cw.affect("live") robot.joints.set("shoulder_pan", 45, degrees=True) # moves the physical robot ``` *** ## Live Video Streaming During teleoperation, live camera feeds from the robot are streamed via WebRTC directly into the dashboard. You can view one or multiple camera feeds alongside the 3D digital twin view. Supported camera types: * **Standard cameras** (USB/CSI via OpenCV) * **Intel RealSense** (RGB + depth) The media service also exposes a twin-scoped MQTT command channel for media-control operations on active WebRTC streams. This lets edge drivers and teleoperation clients request media-service actions without changing the WebRTC signaling topics. See the [Python SDK video streaming docs](/overview/tools/python-sdk#video-streaming-webrtc) for details on setting up camera streams from edge devices. *** ## Prerequisites Create a [digital twin](/feature-reference/digital-twins) for your robot in an [environment](/feature-reference/environment-editor/index). Install and configure [Cyberwave Edge](/feature-reference/edge/overview) on the machine connected to the robot hardware. Pair the physical robot with the digital twin via the CLI — see the [Edge overview](/feature-reference/edge/overview). *** ## Latency A small delay between operator input and robot response is expected in any teleoperation system. The Cyberwave teleoperation stack uses WebRTC for video and MQTT for control commands, keeping end-to-end latency low enough for hands-on robot work. *** ## Video Walkthroughs End-to-end: catalog to physical robot deployment with a Unitree Go2 Autonomous rover mission with AI-driven analysis in simulation *** ## Next Steps Full SDK reference for live robot control Configure twin capabilities and sensors Automate operations with visual workflows ## Shared gamepad settings In **Control → Overview**, open **Input settings** beside a saved gamepad to change its enable button and stick dead zone for all its action mappings. New mappings reuse those settings. Catalog saves apply to asset defaults; Workbench saves apply to that twin. An input already in use keeps its current settings until you explicitly use the update. # Waypoint reachability Source: https://docs.cyberwave.com/feature-reference/environment-editor/waypoint-reachability See at a glance whether a robot arm can actually reach a waypoint you're placing. When a waypoint is attached to a robot arm, a small badge above it tells you whether the arm can actually put its tool there — updating live as you drag. Hover the badge to see the reason in full. ## What the badges mean | Badge | Meaning | What to do | | ----------- | ---------------------------------------------------------------- | ------------------------------------ | | **✓** green | The arm can reach this pose. | Nothing. | | **⟳** amber | The arm can reach the *position*, but not at that *orientation*. | Rotate the waypoint. | | **✕** red | The arm cannot reach the position at all. | Move the waypoint closer to the arm. | | *no badge* | Not checked. | Nothing — see below. | Each badge carries its own symbol as well as a colour, so it stays readable without relying on telling red from green. No badge is the normal state for any waypoint this doesn't apply to, which is most of them: waypoints for mobile robots, waypoints placed in the environment rather than attached to an arm, and arms without a robot description to solve against. Those waypoints look exactly as they always have. A badge only ever appears after a successful check, so a bare waypoint never means "probably fine" — and a check that fails removes the badge rather than guessing. ## When it applies The waypoint has to be attached to an arm's base link — set the waypoint's reference frame to the arm. Waypoints attached to *other waypoints* inherit the chain, so a waypoint attached to a waypoint attached to an arm is checked against that arm. Dragging a parent waypoint re-checks everything attached beneath it. Checks run while you have edit rights on the environment. ## While you drag Verdicts update continuously as you move a waypoint. Dragging a waypoint far outside the arm's reach shows **✕** immediately. Nearer the edge of the workspace the badge fades for a moment while the answer is computed — a faded badge means "still deciding", not a verdict. Only the waypoint you're dragging is re-checked, along with anything attached to it. The rest keep the verdict they already had. ## Limitations * **Reach only, not safety.** The check ignores collisions — with the scene and with the arm itself. A green waypoint can still be a pose you don't want the arm to take. * **One waypoint at a time.** Each waypoint is judged on its own, starting from the arm's current pose. Running a path visits waypoints in order from wherever the previous one left the arm, so a waypoint that checks out on its own can still fail as part of a longer path. * **Green is about the arm, not about the run.** The check works harder to find a solution than running the waypoint does, so a pose near the edge of what the arm can hold — usually an awkward wrist angle rather than a distant position — can show green and still fail to run. Rotating the waypoint slightly is normally enough. * **Waypoints attached to a moving link stay blue.** Only the arm's base link is supported as a reference frame. # Hand-eye calibration Source: https://docs.cyberwave.com/feature-reference/hand-eye-calibration Measure where a camera actually sits on a robot arm, instead of entering the mount offset by eye ## What it is When you dock a camera twin to an arm link, the mount offset starts as a value you typed in the editor. That is fine for previewing a field of view and not good enough for manipulation: every pixel-to-world calculation inherits the error. Hand-eye calibration measures that offset. You hold a printed board still, reorient the wrist a dozen times, and Cyberwave solves for the camera's pose on the link — then writes it to the camera twin's docking offset. Eye-in-hand only: the camera must be mounted on a moving link. You can run it two ways: from the dashboard on a supported robot, or from the SDK. ## Before you start * Dock the camera twin to the arm link it is physically mounted on. * Print a ChArUco board and **measure the squares with calipers**. Printers rescale, and the square size is the only scale input — a 2% error becomes a 2% range error. * Clamp the board so it cannot move for the whole session. ## From the dashboard Select the docked camera twin in the environment editor and open **Hand-eye calibration**. The panel shows the arm and link it will measure against, plus the last calibration if there is one. Click **Calibrate hand-eye**. The robot then guides you through the run in a calibration alert: 1. Hand-guide the wrist to a new orientation and let it settle. 2. Click **Capture sample**. The alert counts your captures and tells you if the board was not found in one — that capture is not added, so reposition and retake. 3. After at least three captures, **Solve** appears. Click it when you have a dozen. 4. Check the stability figure — that is the number the verdict is keyed on — then **Apply to docking offset**, or **Capture more** to tighten it first. Available on robots whose camera is managed by the same edge driver as the arm — the SO-101 today, and any driver whose maintainer has wired up its arm and camera for it. For anything else, use the SDK. **Reorient, don't just move.** Sliding the wrist around at a fixed orientation cannot determine the camera's orientation, no matter how many captures you take. Tilt it about several different axes. If the captures don't constrain the answer, the solve refuses rather than returning a guess. ## From the SDK If you know your camera's intrinsics (`fx`, `fy`, `cx`, `cy`), pass them in. If you don't, omit `intrinsics` and they are solved from the same board views you capture for the calibration. ```bash theme={null} pip install "cyberwave[calibration]" ``` ## Capturing ```python theme={null} from cyberwave.calibration import CharucoBoard, HandEyeSession session = HandEyeSession( camera_twin=camera, arm_twin=arm, fk_frame="wrist_link", # the link the camera is docked to board=CharucoBoard(squares=(5, 7), square_size_m=0.030, marker_size_m=0.022), intrinsics={"fx": 615.0, "fy": 615.0, "cx": 319.5, "cy": 239.5}, ) for _ in range(12): input("Reorient the arm, let it settle, then press Enter...") session.add_sample(base_to_gripper=gripper_pose_4x4) result = session.solve() ``` As above, reorient the wrist rather than sliding it — `solve()` refuses rather than returning a guess when the captures don't constrain the answer. Keep the board still for the whole session; if you bump it, call `session.clear()` and start over. `add_sample()` waits for the arm to stop before grabbing a frame, and checks it is still in the same place afterwards — an arm that had not settled would otherwise pair one position's image with another position's pose, which nothing downstream can detect. Captures that fail the check raise `HandEyeSyncError` and are discarded rather than stored. If your arm reports joint states slowly, raise `settle_timeout_s`. Pass `settle=False` to turn the check off, and note it is skipped automatically when you supply your own `image=`. ## Checking the result **Start with stability.** It re-solves with each capture dropped in turn and reports how far the answer moves — so it asks the question you actually have, "will this number hold?", rather than "do my captures agree with each other?". ```python theme={null} print(result.leave_one_out.max_stddev_m) # under ~4 mm is good, over ~8 mm is not ``` Measured on an SO-101 wrist camera, runs whose mount position was reproducible across independent sessions land at 1.9–3.5 mm; ill-conditioned ones reach 7.7–24 mm, almost entirely along the camera's optical axis. The dashboard's good/borderline/not- usable verdict is keyed on this number. ```python theme={null} print(result.residual_translation_m, result.residual_rotation_deg) ``` The residual is a secondary check — how much the captures disagree with each other, reported as a standard deviation across them. It is worth reading to catch a grossly bad fit, but it tracked working distance more than answer quality on this arm, which is why it is not the headline. A large one usually means, in order of likelihood: wrong intrinsics, a board that moved, or forward kinematics reported about a different link than the camera is docked to. Because it is a standard deviation, it reports *variability*, not offset: a set of captures that are all wrong by the same amount reads low. `max_residual_translation_m` and `max_residual_rotation_deg` carry the worst single capture, so a max several times the residual points at one capture to retake rather than at a bad fit. **Neither number is an error bar.** Both measure internal consistency, not distance from the truth, and they come apart in two ways: * A consistent mistake — poses measured about the wrong link, say — produces a *small* residual and a wrong answer. (Both the dashboard flow and `HandEyeSession` check the link name for you, which is why that particular mistake is hard to make.) * If your captures rotate about only slightly different axes, the problem is ill-posed and every statistic flatters it. Tilt the wrist about genuinely different axes between captures rather than sliding it around — rotation variety is what makes the solve possible. ## Intrinsics Intrinsics are an input the hand-eye solve cannot recover from: every board pose inherits their error, and it shows up only as an inflated residual with nothing pointing at the cause. So if you don't pass any, they get solved properly: ```python theme={null} session = HandEyeSession(..., intrinsics=None) # or just omit it ``` Every capture is accepted or refused on the spot — finding the board's corners needs no camera model, only turning them into a pose does — and the camera model is fitted once, at `solve()`, from every view you captured. Nothing is held back and nothing is discarded. ```python theme={null} print(result.solved_intrinsics.rms_reprojection_px) # < 1 px is good print(result.solved_intrinsics.principal_point_is_centred) ``` Check both. A high RMS means redo it with more varied views; a principal point far from the image centre usually means the board spec is wrong rather than the sensor being genuinely offset. Vary the board's **angle and distance**, not just its position — views that are all face-on leave the focal length poorly constrained however many you take. And intrinsics are per-resolution: mixing frame sizes in one session is rejected. ## Cross-checking the solve `session.solve()` re-solves with each capture dropped in turn and attaches the result: ```python theme={null} print(result.leave_one_out.max_stddev_m) # movement when one capture is dropped print(result.leave_one_out.worst_sample_index) # capture to re-take first ``` `leave_one_out` answers a question the residual cannot. The residual asks whether your captures agree with each other; leave-one-out asks whether the answer holds up when the evidence changes. A calibration that moves millimetres when any single capture is dropped is not one to trust, however tight its residual. `leave_one_out` is `None` only when dropping a capture would leave too few to solve at all — so with the three captures a solve needs, or when the captures are so alike that every reduced set is degenerate. At low capture counts the spread says a lot about *which* capture was removed, so read it as weak evidence and check `subset_count` for how many re-solves it came from. `worst_sample_index` names the capture to re-take first when the spread is wide. Pass `validate=False` to skip it. ## Saving ```python theme={null} if result.residual_translation_m < 0.005: camera.calibration.set(result, board=session.board) ``` This updates the camera twin's docking offset, so the 3D view and any exported scene both place the camera where it really is. The solve details — residuals, sample count, board, and the intrinsics you supplied — are stored alongside it. Read it back with `camera.calibration.get()`. `camera.calibration.delete()` forgets the record but leaves the mount offset in place. ## When the result looks wrong The SO-101 driver ships `so101-handeye-debug`, which runs the same calibration with Cyberwave taken out of the loop — no API key, no twins, no MQTT — and writes every frame, joint reading, board pose and solve to a run directory. ```bash theme={null} so101-handeye-debug selftest # is the pipeline itself sound? so101-handeye-debug board # does the print match the spec? so101-handeye-debug capture --fov 60 --fk-frame gripper # capture, saving everything ``` Because the frames and poses are all on disk, you can re-solve a run offline with one input changed at a time and see exactly what moves: ```bash theme={null} so101-handeye-debug intrinsics --run $RUN # measure the intrinsics you guessed so101-handeye-debug solve --run $RUN --intrinsics-from-fit so101-handeye-debug solve --run $RUN --drop 4 # was one capture carrying the residual? ``` Full options: [SO-101 driver README](https://github.com/cyberwave/cyberwave-edge-python-so101#so101-handeye-debug). # cyberwave.yml manifest Source: https://docs.cyberwave.com/feature-reference/manifest Schema reference for cyberwave.yml configuration files ## Overview Every Cyberwave Cloud Node and edge deployment is configured via a `cyberwave.yml` manifest file. The manifest declares install scripts, inference/training commands, worker modules, hardware requirements, and MQTT settings. ## Minimal example ```yaml theme={null} cyberwave: inference: inference.py gpu: true ``` ## Full field reference | Field | Type | Default | Description | | -------------- | -------------- | ----------- | --------------------------------------------- | | `version` | string | `"1"` | Schema version | | `name` | string | — | Node display name | | `install` | string | — | Shell command run once at startup | | `inference` | string | — | Module (`.py`) or shell command for inference | | `training` | string | — | Module (`.py`) or shell command for training | | `workers` | list | — | Worker `.py` files using hook decorators | | `requirements` | list | — | pip package specs | | `models` | list | — | Model IDs to pre-download | | `input` | string or list | — | Input type declaration | | `gpu` | boolean | `false` | Whether GPU is required | | `runtime` | string | — | Known runtime ID for zero-code mode | | `model` | string | — | Model file path (used with `runtime`) | | `profile_slug` | string | `"default"` | Profile for workload routing | | `resources` | object | — | `memory` and `cpus` constraints | ## Dispatch modes The `inference` and `training` fields auto-detect their dispatch mode: * **Module mode** (`inference.py`): imports the file and calls `infer(**params)` directly * **Shell mode** (`python server.py {body}`): spawns a subprocess (existing behaviour) ## Validating locally ```bash theme={null} cyberwave manifest validate cyberwave manifest validate path/to/cyberwave.yml --lenient ``` ## Legacy compatibility Both `cyberwave:` and `cyberwave-cloud-node:` wrapper keys are supported. The `install_script:` field (legacy) is normalised alongside `install:` (new). # Edge worker container Source: https://docs.cyberwave.com/feature-reference/ml-models/edge-worker Run ML worker scripts on edge devices with managed lifecycle, hot-reload, and health monitoring ## Overview Edge Core manages a dedicated worker container (`cyberwave-worker-{env_uuid[:8]}`) on each edge device. Worker scripts run inside this container with access to the Zenoh data bus, cached model weights, and all environment twin data. One worker container runs per edge device (not per twin). Workers can consume data from all twins in the environment simultaneously. ## Worker Directory Place Python worker scripts in the edge config workers directory: | Platform | Path | | -------- | ----------------------- | | All | `~/.cyberwave/workers/` | ## Model Requirements Declare model dependencies in `cyberwave.yml` inside the workers directory: ```yaml theme={null} models: - yolov8n - background-subtraction ``` Edge Core pre-downloads listed models before starting the worker container. Models are also auto-detected from `cw.models.load("...")` calls in worker Python files. ### Picking the model format Each catalog model declares an **edge runtime** that tells the worker how to load the checkpoint. The runtime selector lives in the model editor (`/models` → "Add Model" or "Edit"), and is also accepted as a typed `edge_runtime` field on `POST /api/v1/mlmodels` and `PUT /api/v1/mlmodels/{uuid}`. The well-known runtimes mirror the loaders in the Cyberwave Python SDK's `cyberwave.models.runtimes` registry: | Runtime | Extension | Loader | | ---------------- | ------------------------------ | ------------------------------------------------------------------ | | `ultralytics` | `.pt` | YOLOv5/8/11 via the Ultralytics package | | `onnxruntime` | `.onnx` | ONNX Runtime (CPU, CUDA EP on the GPU image) | | `opencv` | `.xml` / `.caffemodel` | OpenCV Haar / DNN models | | `tflite` | `.tflite` | TensorFlow Lite | | `torch` | `.pt` / `.pth` | TorchScript / raw PyTorch | | `tensorrt` | `.engine` / `.trt` | TensorRT engines (GPU image only) | | `whisper_cpp` | `.gguf` / `.bin` | Whisper.cpp speech-to-text on CPU edge devices | | `faster_whisper` | CTranslate2 weights (HF cache) | faster-whisper STT on edge CPU/GPU | | `hailo` | `.hef` | Hailo accelerator (`hailo_platform`) on Pi 5 + AI HAT+ / Pi AI Kit | Custom values are accepted via the editor's "Other" entry — used today for framework-specific identifiers like `sam2`, `sam3`, and `depth_anything_v2` that don't have an SDK loader yet but still need to round-trip through the catalog. `GET /api/v1/mlmodels/edge-runtimes` returns the current well-known list (no auth required) so external tools can mirror the dropdown without hard-coding it. ONNX YOLO postprocessing applies per-class non-max suppression with a default IoU threshold of `0.7` so swapping `yolov8s.pt` for `yolov8s.onnx` produces the same number of boxes per object instead of a cluster of overlapping anchors. Override per-call via `model.predict(frame, iou=0.5)` (stricter) or `iou=1.0` (raw output, no suppression). NMS-free detectors (YOLO26's default one-to-one head, YOLOv10) emit `[max_det, 6] = [x1, y1, x2, y2, conf, class_id]`; the SDK's ONNX runtime detects this layout automatically and parses it without the anchor-decoding step. The model's one-to-one head is supposed to already be deduplicated, but some exports (open-vocabulary heads especially) can still emit many near-duplicate boxes for one object, so the same `iou` NMS also runs here as a safety net. End-to-end pose / segmentation exports are not decoded yet; re-export those tasks with `end2end=False` until the e2e pose branch lands. Every detection result is additionally capped at `max_detections_per_class` (default `30`) highest-confidence boxes per label, applied after NMS — a backstop for models whose suppression doesn't fully collapse duplicates (open-vocabulary heads like YOLOE are the common case). Pass `model.predict(frame, max_detections_per_class=None)` to disable it. The Ultralytics runtime also defaults every call to `end2end=False` so real NMS runs on the one-to-many head instead of trusting a checkpoint's self-reported "already deduplicated" flag; checkpoints with only a one-to-one head (fused `.pt`, TensorRT, some ONNX exports) fall back to `end2end=True` automatically. ### YOLO ONNX catalog The public catalog ships ONNX twins for the most common YOLO entries — Cyberwave hosts the exported weights at `https://static.cyberwave.com/ml_models/{name}.onnx` so edge nodes can fetch them with no Ultralytics CDN dependency. Roughly 2× faster on CPU than the `.pt` build: | Family | Sizes | Tasks | | ------ | ------------- | -------------------------- | | YOLOv8 | n, s | detect; plus pose (n only) | | YOLO26 | n, s, m, l, x | detect, pose | Pick `Edge Runtime: ONNX Runtime` in the model editor (or `metadata.edge_runtime = "onnxruntime"` via the API) when registering a private fine-tune that you've exported via `YOLO("…").export(format="onnx")`. The SDK's `OnnxRuntime` reads `names` and `kpt_shape` from the ONNX `custom_metadata_map`, so labelled detections and keypoints work out of the box. Segmentation, OBB, and classification ONNX exports are not yet supported by the SDK runtime — use the `.pt` (`ultralytics`) variants for those tasks. ### YOLO Hailo catalog For Hailo-accelerated edge nodes (Raspberry Pi 5 + AI HAT+ and the older Pi AI Kit) the catalog also ships pre-compiled YOLO HEFs straight from the Hailo Model Zoo. Each upstream YOLO checkpoint gets two sibling rows — one per Hailo architecture — because HEFs are hardware-locked: | Slug | Family | Arch | Edge target | | ---------------------------- | ------------- | ------------------ | ------------ | | `yolov6n_h8` / `yolov6n_h8l` | YOLOv6 Nano | Hailo-8 / Hailo-8L | 26 / 13 TOPS | | `yolov8n_h8` / `yolov8n_h8l` | YOLOv8 Nano | Hailo-8 / Hailo-8L | 26 / 13 TOPS | | `yolov8s_h8` / `yolov8s_h8l` | YOLOv8 Small | Hailo-8 / Hailo-8L | 26 / 13 TOPS | | `yolov8m_h8` / `yolov8m_h8l` | YOLOv8 Medium | Hailo-8 / Hailo-8L | 26 / 13 TOPS | Slugs use the `_h8` / `_h8l` suffix on purpose: `cw.models.load("yolov8s_h8")` is enough to route through the SDK's `hailo` runtime — no extra arguments needed. Pick the row that matches your edge target; a Hailo-8 HEF will refuse to run on a Hailo-8L (and vice versa). If you pick the wrong sibling, Edge Core catches it before the download starts: a Gate-3 preflight probes the connected accelerator with `hailortcli fw-control identify` and refuses to fetch a HEF whose `metadata.hw_arch` disagrees with the device, naming the correct sibling in the error message. The preflight is silent when `hailortcli` is not installed on the host — install it via `apt install hailo-all` (or the matching HailoRT package) to enable the check. ### Edge speech-to-text Seeded Whisper.cpp STT models can run from `Audio Track -> Call Model` workflows on Raspberry Pi 4-class devices. The generated worker passes the audio chunk and seeded `download_url` into the local `whisper_cpp` runtime, so the first run downloads missing weights into the Cyberwave model cache. Downstream nodes can use `text`, `transcribed_text`, and `segments`. English GGML checkpoints: **Tiny EN**, **Base EN**, and **Small EN** (Q5\_1). Multilingual checkpoints: **Tiny Multilingual** and **Base Multilingual** — hybrid deployment with `edge_runtime: whisper_cpp` on edge missions and whisper cloud-node fallback (`openai/whisper-tiny` / `openai/whisper-base`) on cloud missions. Use multilingual models when the spoken language is unknown or mixed. Hybrid **Faster Whisper** catalog entries (`faster_whisper` runtime) run on-device when the workflow mission executes on the edge; cloud missions use the whisper cloud node with the same OpenAI model aliases (`openai/whisper-tiny` → `tiny.en`, etc.). Prefer **Faster Whisper Tiny EN** for real-time English streams; use **Whisper Tiny Multilingual Q5\_1** for multilingual edge STT without CTranslate2. ### Model weights resolution For each required model, Edge Core resolves weights in this order: 1. **Local cache (intact).** If `~/.cyberwave/models/{model_id}/...` is present and its SHA-256 matches the manifest, it is used directly. 2. **Cyberwave-hosted signed URL.** If the catalog entry has a checkpoint mirror, Edge Core fetches a signed URL via `GET /api/v1/mlmodels/{uuid}/weights` and downloads from our private bucket. 3. **Upstream weights URL.** If no Cyberwave mirror exists, Edge Core falls back to the public `download_url` from the catalog (e.g. an official Ultralytics release). 4. **Stale cache fallback.** If every download attempt fails but the local file is intact, Edge Core returns the cached file with a warning. This keeps workers running across transient network failures and on permanently air-gapped sites. Operators on air-gapped sites can pre-stage weights by copying them to `~/.cyberwave/models/{model_id}/`. Edge Core computes a SHA-256, infers the runtime from the file extension (`.pt`, `.onnx`, `.engine`/`.trt`, `.tflite`, `.pth`, `.xml`), and writes a sidecar `metadata.json` on the next worker start. To update a pre-staged model, simply overwrite the file in place — Edge Core re-stamps the manifest from disk on the next call (no re-download attempted). Pre-staged files are never auto-overwritten by catalog updates; to force a re-download from Cyberwave, evict the model directory (`rm -rf ~/.cyberwave/models/{model_id}`). ## CLI Commands ```bash theme={null} cyberwave worker start # Start the worker container cyberwave worker stop # Stop the worker container cyberwave worker restart # Restart (re-scans workers, re-downloads models) cyberwave worker status # Show container state and loaded workers cyberwave worker health # Show detailed restart history and circuit-breaker state cyberwave worker logs # Stream worker container logs ``` These commands are also available via `cyberwave-edge-core worker …` if you prefer to use the edge-core CLI directly. ## Hot-Reload on File Changes Edge Core monitors the workers directory every \~15 seconds. When `.py` files are added, removed, or modified, the worker container is automatically restarted with the updated set of workers. A minimum cool-down of 10 seconds between successive automatic restarts prevents rapid churn when files are written incrementally. ## Health Monitoring Edge Core continuously monitors the worker container: * **Restart accounting**: every restart is recorded with timestamp and reason. * **Circuit-breaker**: after 5 restarts in 5 minutes, automatic restarts are suppressed until the window clears. Run `worker health` to inspect the state. * **Spontaneous exit detection**: if the container exits without a deliberate restart, a warning is logged. ## Performance Tuning ### Model warm-up The worker runtime automatically runs two dummy inferences on each loaded model at startup to eliminate cold-start latency (JIT compilation, memory allocation). Cold vs warm latency is logged. You can also warm up models explicitly: ```python theme={null} model = cw.models.load("yolov8n") cold_ms, warm_ms = model.warm_up(input_shape=(640, 640, 3)) ``` ### Frame resolution scaling Set `CYBERWAVE_WORKER_INPUT_RESOLUTION` to downscale incoming frames before they reach your worker hooks. This reduces inference time on constrained devices without changing the camera driver's publish resolution. ```bash theme={null} export CYBERWAVE_WORKER_INPUT_RESOLUTION=640x480 ``` ### Shared memory transport Zenoh shared-memory (SHM) transport offers zero-copy frame delivery between the camera driver and worker containers on the same host. Edge Core leaves `ZENOH_SHARED_MEMORY` **disabled by default** because SHM between Docker containers requires them to share an IPC namespace via `--ipc=host`, which weakens container isolation and has historically been a source of instability in production. To opt in, enable the flag on **both** the publisher and any same-host consumer, and give each container a shared IPC namespace (`--ipc=host`) and a raised locked-memory limit (`memlock=-1` — the default 8 MB cap is too small for a frame pool, and without it the transport silently falls back to copy): ```yaml theme={null} # docker-compose fragment — publisher + same-host consumer services: camera-driver: ipc: host # shared /dev/shm + IPC namespace ulimits: memlock: -1 environment: ZENOH_SHARED_MEMORY: "true" ml-worker: ipc: host ulimits: memlock: -1 environment: ZENOH_SHARED_MEMORY: "true" ``` Under Edge Core, set `ZENOH_SHARED_MEMORY=true` once in its environment and it propagates the flag to the driver and worker containers; with the SDK directly, set it on each container (or pass `ZenohBackend(shared_memory=True)`). Zero-copy applies only to frame-sized payloads; small messages (joint states, etc.) always copy. Optional publisher knobs: | Variable | Default | Purpose | | ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ZENOH_SHM_POOL_BYTES` | 64 MB | Size of the shared-memory pool. Raise for large frames or deep in-flight buffering. | | `ZENOH_SHM_MIN_BYTES` | 4096 | Payloads below this size skip SHM and publish via copy. | | `ZENOH_SHM_ON_EXHAUSTION` | `copy` | Backpressure when the pool is full: `copy` (guaranteed delivery, latency grows under overload) or `drop` (skip the frame, stay low-latency — for live video). | If the pool can't be created, publishing degrades to the copy path with a warning rather than failing. When it's exhausted by a slow consumer, the `ZENOH_SHM_ON_EXHAUSTION` policy decides between copying and dropping the frame. The pool is allocated per frame whether or not a subscriber can use zero-copy, so enable SHM only when a same-host, SHM-capable consumer is actually reading the stream. **A healthy-looking publisher does not prove zero-copy delivery.** The pool is created and used successfully even when no consumer can map it — for example if the containers omit `ipc: host`, each gets its own private `/dev/shm`. In that case the publisher reports SHM enabled and its `shm_frames` counter climbs, while every consumer silently receives ordinary wire copies and you get none of the latency benefit. Those counters are publish-side intent only. The single source of truth is the **receiving** end: a sample is genuinely zero-copy only when `sample.payload.as_shm()` is not `None`. Verify there once when rolling SHM out, rather than trusting the publisher's stats. #### Consuming the stream from your own process The SHM path isn't specific to the ML worker — **any Zenoh peer on the same host can read a driver's frames zero-copy**. To consume from your own process: * **Run it on the same host.** If it's containerized, launch it with `--ipc=host` (or `--ipc=container:`) so it shares the IPC namespace; a process running directly on the host already qualifies. * **Enable SHM in its Zenoh session** — `ZENOH_SHARED_MEMORY=true` via the SDK, or `transport/shared_memory/enabled=true` on a raw Zenoh session. A consumer that leaves SHM off still receives every frame, just copied over loopback instead of zero-copy. * **Subscribe to the driver's channel.** With the SDK, use `DataBus.subscribe(...)` — it resolves the key for you. `memlock=-1` is only needed if your process *also* publishes SHM. Read-side note: a **Python** consumer (SDK or raw `eclipse-zenoh`) receives each frame as a copy — the zero-copy is the transport hop, so it still cuts latency and jitter but not the final ingest copy. A native **C++/Rust** Zenoh consumer can map the shared buffer and read it zero-copy end-to-end. ## GPU Access Edge Core detects the NVIDIA container runtime and passes `--gpus all` to the worker container when available. ### Image variants The worker image is published in four variants on Docker Hub: | Tag | Base | Accelerator | Architectures | Use when | | ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------- | --------------------------------------------------------------------------------------------- | | `cyberwaveos/edge-ml-worker:` | `ubuntu:24.04` | CPU (`onnxruntime`) | `linux/amd64`, `linux/arm64` | No GPU available, or inference is light enough for CPU. | | `cyberwaveos/edge-ml-worker:-gpu` | `nvidia/cuda:12.6.3-runtime-ubuntu24.04` | NVIDIA discrete (`onnxruntime-gpu`) | `linux/amd64` | Edge device has an NVIDIA GPU and `nvidia-container-toolkit` installed. | | `cyberwaveos/edge-ml-worker:-jetson` | `ubuntu:24.04` (arm64) | NVIDIA Tegra iGPU (PyTorch + ONNX Runtime GPU, Jetson AI Lab cu129 wheels; CUDA injected by host at runtime) | `linux/arm64` | Jetson Orin on JetPack 7 (Ubuntu 24.04 / L4T r38). JetPack 6 hosts are not supported. | | `cyberwaveos/edge-ml-worker:-hailo` | `cyberwaveos/edge-ml-worker:` | Hailo-8 / Hailo-8L (`hailo_platform`) | `linux/arm64` | Edge device has a Hailo accelerator exposed at `/dev/hailo0` (e.g. Raspberry Pi 5 + AI HAT+). | The `-jetson` variant uses PyTorch/torchvision/torchaudio and `onnxruntime-gpu` wheels from the [Jetson AI Lab devpi index](https://pypi.jetson-ai-lab.io/jp6/cu129/) (Orin `sm_87` builds), not the amd64 `-gpu` variant's index. The image base is `ubuntu:24.04`; NVIDIA has not yet published an `l4t-jetpack` image for JP7. nvidia-container-runtime injects the host's CUDA driver at container start; the image itself bundles the matching CUDA 12.9 userspace runtime libraries (`libcudart`, `libcublas`, cuDNN) since the Jetson wheels link against system CUDA rather than bundling it. ONNX Runtime exposes `CUDAExecutionProvider` on Jetson, same as the `-gpu` variant. **JetPack 6 hosts are not supported** — JetPack 6's CUDA driver predates what's needed to run a CUDA 12.9 runtime, so only JetPack 7 hosts should pull this tag. Edge Core reads the L4T release from `/etc/nv_tegra_release` and starts a JetPack 6 board on the plain (CPU, multi-arch) tag instead, logging a warning; `CYBERWAVE_JETSON_ALLOW_UNSUPPORTED_L4T=1` forces the `-jetson` tag anyway. This is decided when the worker container is created, so a board already running a `-jetson` worker keeps it across an Edge Core upgrade — remove the container once (`docker rm -f cyberwave-worker`) to pick up the new selection. The `-hailo` variant compiles HailoRT (`libhailort` + `hailortcli` + `pyhailort`) from the MIT-licensed upstream source at [`hailo-ai/hailort`](https://github.com/hailo-ai/hailort) at a pinned tag. The LGPL-2.1 GStreamer plugin (`hailonet`) is left out of the build. The companion kernel driver ([`hailo-ai/hailort-drivers`](https://github.com/hailo-ai/hailort-drivers)) is installed on the host (e.g. via `apt install hailo-all` on Raspberry Pi OS), not in the container — its minor version must match the userspace lib baked into the image. All four variants ship the same Python API. PyTorch/Ultralytics models pick the device automatically; ONNX models gain `CUDAExecutionProvider` only on the `-gpu` variant; `.hef` files load through the `hailo` runtime only on the `-hailo` variant. Edge Core selects the variant automatically based on host capabilities: * **Jetson host detected** (`/etc/nv_tegra_release` present) → appends `-jetson` and adds `--gpus all`. Wins over the `-gpu` branch: on Jetson the nvidia-container-runtime is present too, but the amd64 `-gpu` blob has the wrong `libcuda.so` ABI (desktop/server CUDA vs Tegra CUDA). * **NVIDIA container runtime detected (not Jetson)** → appends `-gpu` to the configured worker image tag and adds `--gpus all`. * **`/dev/hailo0` present and no GPU runtime** → appends `-hailo`, adds `--device /dev/hailo0:/dev/hailo0:rwm` and `--group-add hailo` (on HailoRT \< 4.20 hosts), and sets `CYBERWAVE_REQUIRED_DEVICES=/dev/hailo0` so the image's Gate-4 entrypoint fails fast if the passthrough is missing. * **None** → uses the CPU base image. Jetson takes precedence over the amd64 GPU variant, and GPU takes precedence over Hailo when both are available on the same host; mixing them in a single deployment is not supported. If a variant cannot be pulled (e.g. the `-jetson` image isn't published for your channel yet), Edge Core falls back to the CPU image and logs the demotion. # Model catalog Source: https://docs.cyberwave.com/feature-reference/ml-models/index Browse, filter and register the AI models your workspace can use, and see where each one runs. ## What are AI models? AI models registered in your Cyberwave workspace can process various inputs — video, images, audio, text, or robot actions. They integrate with workflows and can run in the cloud or on edge devices. AI models define **what the model can do** (input types) and **where it runs** (provider). The actual inference happens through the model provider's API or on your edge device. *** ## Browsing the model catalog Search **AI models** by name or provider. Model cards use compact rectangular styling and short workspace/model identifiers; asset cards retain rounded image previews. Browse public models and a single row of your matching workspace models together. Empty personal sections are hidden; **All models / Yours / Public** changes the scope. The left sidebar filters input type, deployment, declared task, vendor, size and edge runtime. On small screens, **Filters** opens a scrollable sheet; **Show results** returns to the catalog. Search, filters, and scope stay in the URL, so returning from a model detail restores your selection. Models must support every selected input; vendor and task selections match any selected value. Selected filters can be removed above the results. ## Model Capabilities Each AI model specifies what inputs it can process: | Capability | Description | Example Use Cases | | -------------------------- | --------------------- | ------------------------------------ | | `can_take_video_as_input` | Process video streams | Surveillance, teleoperation | | `can_take_image_as_input` | Process single images | Quality inspection, object detection | | `can_take_audio_as_input` | Process audio data | Voice commands, anomaly detection | | `can_take_text_as_input` | Process text prompts | Natural language commands | | `can_take_action_as_input` | Process robot actions | Behavior cloning, RL policies | *** ## Model Providers Models can run through different providers: Run on your edge devices using ONNX, TensorRT, or custom inference Use OpenAI, Anthropic, or other cloud AI services Deploy models from Hugging Face Hub Your own inference servers and endpoints *** ## Registering a Model Go to **AI models** in your workspace. Click **Add model**. Fill in the model details: name, description, external ID (model identifier for the provider), provider name (e.g. `openai`, `local`, `huggingface`), and input capabilities. Click **Create**. ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="your_api_key") model = cw.api.src_app_api_mlmodels_create_mlmodel(ml_model_create_schema={ "name": "Object Detector", "description": "YOLOv8 model for detecting warehouse items", "model_external_id": "yolov8n", "model_provider_name": "local", "can_take_image_as_input": True, "can_take_video_as_input": True, "visibility": "private", "tags": ["vision", "detection", "warehouse"] }) print(f"Model UUID: {model.uuid}") ``` *** ## Model Visibility | Visibility | Who Can Access | | ----------- | ----------------------------- | | `private` | Only your workspace members | | `workspace` | All workspace members | | `public` | Anyone (admin-only to create) | *** ## Using Models in Workflows AI models integrate with workflow nodes for automated processing: ```mermaid theme={null} flowchart LR A[Capture Image] --> B[AI model: Detect Objects] B --> C{Found?} C -->|Yes| D[Pick Object] C -->|No| E[Alert Operator] ``` *** ## Try it in the Playground Every model detail page (`/{workspace-slug}/models/{model-slug}` or `/models/{uuid}` for models without a slug) has an interactive **Playground** tab. Gemini Robotics-ER renders detected points as an overlay on your image, VLMs stream back text, `im2mesh` models preview the generated GLB inline, and edge/VLA models surface the exact CLI + SDK commands needed to run them locally. See [Model playground](/feature-reference/ml-models/playground). *** ## Running Inference For cloud-based models, Cyberwave routes requests to the provider: ```python theme={null} response = cw.models.run( model.uuid, prompt="What objects do you see? How should the robot pick them up?", image_url="https://...", ) ``` For local models, run inference on your edge device using your preferred framework (PyTorch, ONNX, TensorRT) and publish results back to Cyberwave via MQTT or the SDK. *** ## Listing Models ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="your_api_key") models = cw.models.list() for model in models: print(f"{model.name} ({model.model_provider_name})") print(f" Video: {model.can_take_video_as_input}") print(f" Image: {model.can_take_image_as_input}") print(f" Text: {model.can_take_text_as_input}") ``` *** ## Vision-Language-Action (VLA) Models VLA models combine vision, language understanding, and action generation for end-to-end robot control. Cyberwave provides infrastructure for running VLA model inference and training on Cloud Nodes. ### Supported VLA Models | Model | Description | Deployment | | ------- | ---------------------------------------- | ---------- | | SmolVLA | Lightweight VLA from HuggingFace LeRobot | Cloud Node | | OpenVLA | Open-source VLA model | Cloud Node | ### Model Weights VLA models store their weights in Cyberwave and expose them via the MLModel API: ``` GET /api/v1/mlmodels/{uuid}/weights → { "signed_url": "...", "expires_at": "..." } ``` This allows Cloud Nodes to fetch model weights on demand and cache them locally. ### Running VLA Inference VLA inference runs on Cloud Nodes using the `CwProcessor` orchestrator: 1. **Weights Download** - Fetched from MLModel API via signed URLs 2. **Camera Binding** - Background threads continuously fetch camera frames 3. **Control Loop** - Observe → Predict → Execute cycle 4. **Action Publishing** - Predicted actions sent to robot via MQTT Learn how to build and deploy VLA models on Cyberwave Cloud Nodes # OpenVLA-OFT training Source: https://docs.cyberwave.com/feature-reference/ml-models/openvla-oft-training Fine-tune OpenVLA-OFT models using the openvla (RLDS) dataset format ## Overview OpenVLA-OFT is a LoRA-based fine-tuning framework for Vision-Language-Action models built on the `openvla-7b` base. Cyberwave supports training and deploying OpenVLA-OFT models on your custom datasets using the `openvla` (RLDS) dataset format. OpenVLA-OFT uses the **openvla (RLDS) dataset format** for training, which differs from the LeRobot v3 format used by SmolVLA. The platform handles format selection automatically based on the model type. *** ## Model Selection When creating an ML model on Cyberwave, select **OpenVLA-OFT** as the model type to automatically route training and inference jobs to a cloud node with the `openvla-oft-policy` profile. *** ## Training Training jobs are dispatched to a Cyberwave Cloud Node. The cloud node: 1. Downloads the dataset in RLDS format (`format=openvla`) 2. Downloads the base model weights (`openvla/openvla-7b` by default) 3. Runs the LoRA fine-tuning loop, routing all metrics to the Cyberwave dashboard 4. Compresses and uploads the final checkpoint to the platform ### Key training parameters | Parameter | Description | Default | | --------------------- | ---------------------------------------------------------------------- | ------- | | `max_steps` | Number of training gradient steps | 50 000 | | `batch_size` | Per-GPU batch size (auto-scaled to camera count if omitted) | auto | | `lora_rank` | LoRA adapter rank | 32 | | `use_l1_regression` | Use L1 regression action head instead of cross-entropy | `true` | | `use_proprio` | Include proprioceptive state in observations | `true` | | `num_images_in_input` | Number of camera feeds used during training (auto-detected if omitted) | auto | *** ## Inference Trained checkpoints can be deployed directly from the Cyberwave platform. The cloud node loads the fine-tuned LoRA weights and streams predictions back to your robot via MQTT. *** ## Dataset format OpenVLA-OFT requires datasets in the RLDS (TensorFlow Datasets) format. When you upload a dataset through the Cyberwave platform, it is automatically converted and made available for download in the `openvla` format. # Model playground Source: https://docs.cyberwave.com/feature-reference/ml-models/playground Interactive UI and code snippets for running AI models from the Cyberwave app ## What is the model playground? The **model playground** is the interactive detail page that lives at `/{workspace-slug}/models/{model-slug}` (or `/models/{uuid}` for models without a slug). It lets you explore, test, and integrate any AI model registered in your workspace or visible in the public catalog. Access the playground from the Model Detail Page. Every card on `/models` also ships a **Playground** button that deep-links straight into the `?tab=playground` view. *** ## What you can do Start with a **task**. In the model catalog, **More filters → Tasks** narrows models by their declared task contracts. On a model page, **Services** explains its tasks, required inputs and output meaning; expand the input/output details when configuring a mapping. This lists supported interfaces, not deployed integrations or tested robot compatibility. Models that support several tasks share one task picker. **Plan steps** takes a goal and returns a task plan; **Free prompt** leaves the prompt open-ended. Task prompts come from the shared task catalog, with model-specific examples where available. Image points, local paths, task plans and joint commands require different downstream services and adapters. The workflow node uses the same task contracts: select **Task**, choose a compatible **Model**, then provide the required observations. **Use example prompt** fills an empty prompt from the selected model's task example. Existing input mappings are retained. In an editable environment workflow, **Configure with AI** opens the existing workflow assistant for the selected node. Edit the request, choose **Plan edit**, then review the proposal before **Review and apply**. This does not activate the workflow. Some models include **recorded examples** showing a previous input and result. Their captions identify the checkpoint and whether depth is relative or metric. They do not run inference. If weights or an execution adapter are unavailable, the page explains the missing setup and keeps its examples readable. The playground auto-detects the model's capabilities (deployment, provider, tags, input modalities, output format) and renders the right UI for each kind: | Playground kind | Typical models | What you can do | | ---------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `vlm-spatial-reasoner` | Models with structured perception or task-planning capabilities | Pick a task, provide its required inputs and inspect the structured output. Image tasks show overlays; task planning accepts a text goal. | | `vlm` | GPT-5, Gemini 2.5 Flash, any text/vision LLM | Send a text prompt (and optionally an image) and see the text response. | | `im2mesh` | Hunyuan3D, TripoSR, single-image-to-3D | Upload an image, submit, and preview the generated GLB inline. | | `vla` | OpenVLA, Pi 0.5 | Configure robot inputs and inspect predicted actions. Sign in to run a VLA model. | | `edge` | YOLOv8, SAM2, any edge-only model | Read the CLI recipe for binding the model to a workspace edge node. | *** ## How inference is plumbed * **Synchronous cloud models** (Google GenAI, OpenAI, or models with an `endpoint_url` deployment) go through `POST /api/v1/mlmodels/{uuid}/run` and return `200 OK` with the output payload (`MLModelRunResultSchema`). * **Asynchronous cloud-node workloads** (e.g. `im2mesh`) return `202 Accepted` with a `workload_uuid` and a `poll_url` pointing at `/api/v1/cloud-node-workloads/{uuid}`. The UI polls the workload and renders the artifact (GLB, image, etc.) once the workload completes. * **Edge models** are not invoked from the browser. The playground shows the exact CLI / SDK commands needed to run the model locally through a Cyberwave edge worker. *** ## When a robot prediction needs setup ### Assisted joint setup for SmolVLA After choosing a robot, **Assist joint setup** proposes how the policy's output columns and units map to that robot. Include details from the checkpoint's training configuration, particularly the gripper convention. Review the assistant's assumptions and edit the mapping or conversion values as needed. Changing an example policy value updates the pose in the 3D viewer immediately. **Save new binding version** stores the mapping in your workspace. You only need read access to the model and robot catalog, plus permission to create in your workspace. Select a saved version explicitly; subsequent saves preserve previous versions. Controller inference and prediction playback use the same conversion. If the source contract changes, or the original model is removed, select an accessible replacement model and use **Adapt an existing binding**. The assistant compares the retained old contract with the selected model and shows changes for review. Saving creates a replacement version; it does not restore deleted weights or automatically activate a controller. Pin checkpoint revisions for reproducible evaluations. The blue ghost is the reference pose from the robot preview. The solid robot shows the converted policy values, with numeric differences displayed per joint. The preview shows the converted pose; it does not run physics or demonstrate task success. This adapter supports absolute joint-position SmolVLA checkpoints whose input and output dimensions match the robot. It cannot turn a generic 32-column base policy into a trained six-joint policy by dropping columns. ### Checkpoint sources A SmolVLA model can declare a stored checkpoint or a Hugging Face `policy_repo_id` with optional `policy_revision`. Stored checkpoints take precedence. If a declared artifact is missing, execution reports the missing artifact instead of silently running a different base model. Hub checkpoints use the same downloaded snapshot for weights, configuration and processors. **Compatible hardware** lists the robots declared for a model. A prediction also needs an output mapping, and pose predictions need the robot's kinematics. These checks happen before a trajectory can replay. * **Model output or joint mapping:** a model editor can choose **Review model setup** to open the existing model settings. Under **Metadata**, compare the output declaration with the checkpoint's training configuration. Joint outputs need their trained joint order; Cartesian outputs need a configured IK service. * **Robot kinematics:** choose **Review robot setup** to open that asset's Control section and review its end-effector and IK configuration. * **Unreachable pose:** choose another target or initial pose before making a new prediction. If you cannot edit the model, the result explains that a model editor must review the configuration. Saved results retain the configuration used for that run. Saving a correction does not approve an old failed result or start a robot. For robot operation, configure the input and service in **Catalog → Control**, then add the asset to an environment. The twin inherits that setup; changes in **Workbench → Control** apply to the twin. Connection and runtime readiness are checked separately when using a control. **Monitor** lets you inspect the setup without changing it. ## Using a model from your code Every playground tab also surfaces copy-paste-ready snippets for the Python SDK, the `cyberwave` CLI, and `curl`. These snippets are specific to the selected model. ### Cloud model (Python SDK) ```python theme={null} from cyberwave import Cyberwave client = Cyberwave() loaded = client.models.load("/models/") result = loaded.predict("./photo.png", prompt="Describe this image") print(result) ``` ### Edge model (CLI) ```bash theme={null} cyberwave model list cyberwave model bind --model --twin-uuid --camera front ``` ### Direct HTTP (cURL) ```bash theme={null} curl -X POST "$CYBERWAVE_BASE_URL/api/v1/mlmodels//run" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "hello"}' ``` *** ## See also * [Model catalog](/feature-reference/ml-models) * [Edge Worker](/feature-reference/ml-models/edge-worker) * [Deploying Models](/tutorials/train-vla-cyberwave) * [Playground API reference](/api-reference/models/playground) — endpoint URLs, request/response schemas, output formats # SmolVLA training Source: https://docs.cyberwave.com/feature-reference/ml-models/smolvla-training Train SmolVLA models using the LeRobot v3 dataset format ## Overview SmolVLA is a lightweight Vision-Language-Action model optimized for edge deployment. Cyberwave supports fine-tuning SmolVLA models on your custom datasets using the LeRobot v3 dataset format. SmolVLA models use the **LeRobot v3 dataset format** for training, which differs from the TFDS format used by OpenVLA models. The platform handles format conversion automatically. *** ## Model Selection When starting a new training: 1. Navigate to **AI → Training** in your environment 2. Select **SmolVLA** from the available model architectures 3. The platform will automatically use the LeRobot training pipeline Only models with `is_trainable: true` appear in the training model selection. SmolVLA is pre-configured as trainable. *** ## Dataset Conversion When you start training with a SmolVLA model, the platform: 1. Joins your episode parquet files into a single dataset 2. Converts the OpenVLA-format parquet to LeRobot v3 format 3. Handles camera role mapping (primary, wrist, secondary) 4. Encodes video frames using AV1 codec (configurable) The conversion is cached — subsequent trainings with the same dataset and configuration skip the conversion step. *** ## Training Parameters SmolVLA training supports: | Parameter | Description | Default | | ------------- | ------------------------------ | --------- | | `fps` | Target frames per second | 30 | | `use_videos` | Store frames as MP4 videos | true | | `vcodec` | Video codec | libsvtav1 | | `num_cameras` | Number of camera streams (1-3) | 1 | *** ## Camera Configuration Camera roles are mapped to LeRobot conventions: * `primary` → `observation.images.primary` * `wrist` → `observation.images.wrist` * `secondary` → `observation.images.secondary` Configure camera roles in the training wizard or via the API. *** ## Training Workflow ```mermaid theme={null} flowchart TD A[Start Training] --> B{Model Type} B -- "SmolVLA" --> C[Convert to LeRobot v3] C --> D[Upload Dataset Zip] D --> E[Cloud Node Training] E --> F[Model Checkpoint] B -- "OpenVLA" --> G[Convert to TFDS] G --> H[Cloud Node Training] H --> F ``` *** ## Deployment After training completes: 1. Deploy the trained model as a controller policy 2. Assign the VLA controller to your robot twin 3. Use natural language prompts to control the robot SmolVLA models are optimized for edge inference, making them suitable for real-time robot control with lower latency than larger VLA models. *** ## Related * [Train VLA Models](/tutorials/train-vla-cyberwave) — Complete training tutorial * [Model catalog](/feature-reference/ml-models) — Model capabilities and providers * [Deploy Models](/tutorials/train-vla-cyberwave) — Deployment options ## Reuse camera setup Open **Camera setup** on a model to review its cameras and mounting positions in another environment. Saved asset and twin slugs help match resources across installations. Resolve missing cameras or changed assets before applying, then restart simulation. Model owners can also save an environment setup as a new recommendation while retaining the setup recorded with training data. The same training flow has experimental support for **π0 (LeRobot)** and **π0.5 (LeRobot)**. Fine-tune for your robot and review its camera and joint requirements; a base policy is not a ready-to-run SO101 controller. Full π-model training and task success have not yet been validated in this integration. # Speech-to-text models Source: https://docs.cyberwave.com/feature-reference/ml-models/speech-to-text Transcribe robot audio with Whisper models in workflows, REST calls, or edge workers Cyberwave exposes speech-to-text as an `MLModel`, not as a ROS intelligence layer. Audio goes in, a JSON transcript comes out, and the same model can be called from `POST /api/v1/mlmodels/{uuid}/run` or a workflow `CALL_MODEL` node. The default catalog model is Whisper Large v3: ```json theme={null} { "audio_url": "https://example.com/audio.wav", "language": "auto", "task": "transcribe" } ``` The Whisper Cloud Node returns: ```json theme={null} { "text": "...", "segments": [], "language": "en" } ``` Use this when a microphone driver uploads audio and a workflow needs to pass the transcript into a downstream controller policy, planner, or human-in-the-loop step. # Tasks and outputs Source: https://docs.cyberwave.com/feature-reference/ml-models/structured-actions The canonical catalog of structured tasks a Cyberwave AI model can run, and how to parse their output. A **structured action** is a preset that tells the Playground how to shape the prompt and how to parse the model response so the result comes back as machine-readable JSON (points, bounding boxes, segmentation masks) instead of a free-form string. You pick one when calling the Playground `/run` endpoint, either from the UI, the HTTP API, or the Python SDK: ```python theme={null} import cyberwave as cw client = cw.Cyberwave(api_key="...") result = client.mlmodels.run( "acme/models/gemini-robotics-er", image="scene.jpg", prompt="cups", structured_task="detect_points", ) print(result.output) # [{"point": [512, 433], "label": "red cup"}, ...] ``` The catalog below is the **single source of truth** for structured actions. It is authored in `cyberwave-backend/src/lib/structured_actions.py`, mirrored in the Python SDK as `cyberwave.STRUCTURED_ACTIONS`, and served live at `GET /api/v1/mlmodels/structured-actions` so the frontend, SDKs, and this doc page all agree. *** ## The catalog | `structured_task` | `output_format` | Renders as | Use it for | | ----------------- | --------------- | ---------------------------------------- | ---------------------------------------------------------------- | | `free` | `text` | Raw string | Any prompt you want passed through unchanged. No output parsing. | | `caption` | `text` | Raw string | One-sentence description of the input image. | | `detect_points` | `points` | Dots overlaid on the image | "Where is X?" — object localisation, keypoint tasks. | | `detect_boxes` | `boxes` | Bounding boxes overlaid on the image | Classical object detection. | | `segment` | `masks` | Tinted silhouettes overlaid on the image | Instance segmentation. | Each action carries a **default prompt template** the backend injects when you pass `structured_task=...`. For example, `detect_points` expands `prompt="cups"` into: ``` Detect cups in the image. Return a JSON array of objects of the form {"point": [y, x], "label": ""} where each point is in [y, x] normalized to 0-1000. Only output the JSON array. ``` This matches the [Gemini Robotics ER](https://ai.google.dev/gemini-api/docs/robotics-overview) contract. Other vendors (Molmo's `` tags, PaliGemma's `` tokens) use their native grounding syntax and the backend passes your raw `prompt` through unchanged when it doesn't know how to rewrite it for that provider. *** ## Output schemas ### `points` — `output_format: "points"` ```json theme={null} [ { "point": [523, 488], "label": "red cup" }, { "point": [714, 232], "label": "green mug" } ] ``` * `point` — `[y, x]` normalized to `0..1000`. * `label` — optional human-readable tag. Render on an image (frontend): `` component. Render on an image (Python): `cw.save_annotated_image(img, result, "out.png")`. ### `boxes` — `output_format: "boxes"` ```json theme={null} [ { "box_2d": [100, 150, 400, 650], "label": "bottle" } ] ``` * `box_2d` — `[ymin, xmin, ymax, xmax]` normalized to `0..1000`. ### `masks` — `output_format: "masks"` ```json theme={null} [ { "box_2d": [120, 80, 480, 510], "mask": "iVBORw0KGgoAAAANSUhEUgAAA...", "label": "fork" } ] ``` * `box_2d` — region the mask applies to. * `mask` — base64-encoded PNG (may be prefixed with `data:image/png;base64,`). Luminance of the PNG defines the silhouette within `box_2d`. *** ## Which models support which action? Capability is derived from the model's metadata, so the list stays in sync as you seed new entries. In code: ```python theme={null} from cyberwave import STRUCTURED_ACTIONS for action in STRUCTURED_ACTIONS: print(action.id, action.output_format, action.description) ``` The SDK mirror carries `id`, `label`, `description`, `output_format`, and `requires_image`. Prompt templates and result schemas are server-side — read them from `GET /api/v1/mlmodels/structured-actions` when you need the live contract. Rules applied server-side (see `src/lib/structured_actions.py::_supports_any_spatial`): 1. The model must take an image as input (`can_take_image_as_input: true`). 2. Output format must be `json` (or unset). 3. Any one of: * metadata declares `point_format` or `bounding_box_format`, * tags include `spatial-reasoning`, `spatial-reasoner`, `grounding`, `visual-grounding`, `pointing`, or `object-detection`, * `model_external_id` starts with `gemini-robotics-er`, `molmo`, or `paligemma`. `caption` is supported by any image-capable model; `free` is supported by every text-capable model (default). *** ## Parsing hints The backend is lenient with provider output: * Strips triple-backtick code fences (`json ... `) some models wrap JSON in. * Falls back to the first `[...]` or `{...}` block when the payload has surrounding prose. * Returns `raw` on every response so you can debug when parsing fails. When you call the Python SDK, `result.output` is already parsed JSON. When you call the HTTP API, parse as standard JSON and branch on `output_format`: ```python theme={null} import requests r = requests.post( f"{API}/api/v1/mlmodels/{uuid}/run", headers={"Authorization": f"Token {TOKEN}"}, json={"prompt": "cups", "image_base64": b64, "structured_task": "detect_points"}, ).json() if r["status"] != "completed": # Async workload — poll r["poll_url"]. ... elif r["output_format"] == "points": for p in r["output"]: draw_point(image, *p["point"], label=p.get("label")) ``` *** ## Annotating images with the result Once you have the output, you usually want to **bake it onto the image** so you can email it, archive it, or attach it to an audit log. The SDK ships a one-liner for that: ```python theme={null} import cyberwave as cw result = client.mlmodels.run( "acme/models/gemini-robotics-er", image="scene.jpg", prompt="cups", structured_task="segment", ) cw.save_annotated_image("scene.jpg", result, "scene.annotated.png") ``` `save_annotated_image`: * Renders each point / box / mask onto the original image. * Writes a **PNG tEXt chunk keyed `cyberwave.run`** with the raw JSON output, the model UUID/slug, and the structured task. * The result is self-describing — any consumer can recover the parsed output from the image alone: ```python theme={null} import cyberwave as cw meta = cw.read_annotated_metadata("scene.annotated.png") print(meta["output_format"], len(meta["output"])) # masks 3 ``` Use `embed_metadata=False` to opt out of the embedded JSON (e.g. when sending the image to a third party). *** ## Extending the catalog 1. Add a new `StructuredAction` to `cyberwave-backend/src/lib/structured_actions.py::STRUCTURED_ACTIONS`. 2. If the output needs a new parse branch, update `MLModelPlaygroundService._parse_output`. 3. Mirror the action in `cyberwave-sdks/cyberwave-python/cyberwave/models/playground.py` (`STRUCTURED_ACTIONS`). The SDK test `tests/test_mlmodels_actions.py::TestBackendAlignment` will fail until the two files agree. 4. Add a frontend overlay if the new `output_format` is visual. 5. Update this page. ### Minimum path for adding a new model / provider / output format * **New model, existing output format**: * Seed or create the model with backend-computed metadata (`playground_kind`, `allowed_structured_tasks`, `execution_surfaces`, `sdk_load_id`) and add tests. * No new frontend overlay or SDK type adapter should be needed. * **New provider wire format, existing structured action**: * Add one adapter in `cyberwave-backend/src/lib/mlmodel_output_adapters.py`. * Keep provider-specific parsing out of API routers and services. * **New output format**: * Add the backend schema/action first. * Add a frontend renderer only if the format is genuinely new. * Update the SDK only if the format can map cleanly onto `PredictionResult`; otherwise preserve the raw structured payload. Treat the backend API response as the source of truth. Frontend and SDK consumers should prefer `playground_kind`, `allowed_structured_tasks`, `execution_surfaces`, and `sdk_load_id` from the backend instead of recomputing them locally. # Bring your own model Source: https://docs.cyberwave.com/feature-reference/ml-models/uploading-your-model Bring your own model into Cyberwave — call your own API, or hand Cyberwave code to run — and use it in workflows, the Playground, and the SDK. Custom models are currently available in **early access**. Reach out to your Cyberwave contact to enable it for your workspace. ## Concepts A **custom model** is an [AI model](/feature-reference/ml-models/index) you register yourself, instead of picking one from the catalog. There are two kinds: Your model already runs somewhere — your own inference server, a HuggingFace Inference Endpoint, a colleague's project. Cyberwave calls it over HTTP whenever the model is used. You give Cyberwave a Python function; Cyberwave runs it for you on demand. No servers to keep online yourself. Both kinds are ordinary `MLModel` rows once created — they show up in the model catalog, can be selected in a workflow's **Call Model** node, and run through the same `POST /mlmodels/{uuid}/run` endpoint and Playground as any built-in model. Custom models are always scoped to `private` or `workspace` visibility (never made public to other workspaces). ### Describing inputs and outputs Every custom model declares its inputs and outputs with `metadata.io_schema` — a list of named, typed ports: ```json theme={null} { "io_schema": { "inputs": [ { "name": "prompt", "type": "text", "required": false }, { "name": "frame", "type": "image", "required": true } ], "outputs": [{ "name": "detections", "type": "json" }] } } ``` Supported types: `text`, `image`, `audio`, `video`, `json`, `number`, `boolean`, `array`. `video` is a reference to a stored recording (a whole clip), not a single live frame — see [Passing a recording as input](#passing-a-recording-as-input). Custom port contracts can also declare data meaning, such as units, coordinate frame and joint order. Two array outputs are not interchangeable merely because their sizes match. Review the mapping when replacing a model; reload its latest configuration if a contract update reports a conflict. Existing untyped models retain their current behavior. Only upload or point at code and endpoints you trust. Custom models run without additional sandboxing today — treat them the same way you'd treat any other code you run on your own infrastructure. *** ## Upload a model hosted behind your API Use this when the model already runs somewhere reachable over HTTPS. Create the model with `model_provider_name: "custom-api"` and your endpoint configuration in `metadata`. ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="your_api_key") model = cw.api.src_app_api_mlmodels_create_mlmodel(ml_model_create_schema={ "name": "Warehouse Defect Classifier", "description": "Calls our own defect-detection API", "model_external_id": "defect-classifier-v1", "model_provider_name": "custom-api", "visibility": "private", "can_take_image_as_input": True, "output_format": "json", "metadata": { "endpoint_url": "https://api.example.com/v1/classify", "http_method": "POST", "payload_template": { "model": "{model_id}", "image": "{image_url}" }, "response_key": "output", "timeout_seconds": 30, "max_retries": 1, "io_schema": { "inputs": [{ "name": "frame", "type": "image", "required": True }], "outputs": [{ "name": "defects", "type": "json" }] } } }) print(model.uuid) ``` `payload_template` values may use the placeholders `{prompt}`, `{model_id}`, and (for `video` inputs) `{video_url}` — Cyberwave substitutes them into the JSON body it sends to `endpoint_url`. `response_key` names the top-level field in your endpoint's JSON response that holds the result. `timeout_seconds` defaults to `120` and is a budget for the **whole** call, retries included — `max_retries` never extends it. Values outside the allowed range are clamped; unparseable values fall back to the default. A few `metadata` keys are reserved for the Cyberwave platform and are rejected on create and update: `cloud_node_profile_slug`, `cloud_node_result_type`, `fallback_provider`, and `fallback_model_id`. Credentials are write-only: once set, Cyberwave never returns the secret value again — only whether one is configured. ```bash theme={null} curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/mlmodels//credential" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "auth_type": "bearer", "secret": "sk-your-endpoint-token" }' ``` `auth_type` is one of `none`, `bearer`, `api_key_header` (also set `header_name`, e.g. `"X-API-Key"`), or `basic`. Remove a credential with `DELETE .../credential`. Run one real call against your endpoint to confirm the config: ```bash theme={null} curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/mlmodels//test-call" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"image_url": "https://example.com/sample.jpg"}' ``` This is a real inference against your endpoint, so it consumes credits like any other run. It requires `metadata.endpoint_url` to be set. The model now behaves like any catalog model — run it directly, from the Playground, or from a workflow's **Call Model** node. ```python theme={null} result = cw.models.run(model.uuid, image_url="https://example.com/frame.jpg") ``` *** ## Upload a model and let Cyberwave host it Use this when you don't want to run your own server — give Cyberwave a Python function and (optionally) a weights file, and Cyberwave runs it on demand. Your code must define one function: ```python theme={null} def run(inputs: dict, artifacts_dir: str | None) -> dict: # inputs matches your declared io_schema.inputs, e.g. {"prompt": "...", "frame": "..."} # artifacts_dir is a local path to your downloaded weights, or None if you didn't upload any ... return {"detections": [...]} # matches your declared io_schema.outputs ``` The base runtime ships with `torch`, `onnxruntime`, `ultralytics`, `opencv`, `numpy`, `pillow`, and `transformers` pre-installed — import them directly from `run()`. Installing extra packages at run time isn't supported yet. All `custom-hosted` models run on GPU-backed compute today, even a small model that would run fine on CPU. You can set `metadata.device` to `"cpu"` or `"gpu"` now to declare which one your model actually needs — it's validated and saved, but **not yet used to choose your compute**: every workload still runs on GPU regardless of this value. Setting it today costs you nothing and means no changes are needed on your side once CPU-tier compute ships. ```python theme={null} model = cw.api.src_app_api_mlmodels_create_mlmodel(ml_model_create_schema={ "name": "My Detector", "description": "Custom ONNX detector, hosted by Cyberwave", "model_external_id": "my-detector-v1", "model_provider_name": "custom-hosted", "visibility": "private", "can_take_image_as_input": True, "output_format": "json", "metadata": { "code": open("run.py").read(), "device": "cpu", "io_schema": { "inputs": [{ "name": "frame", "type": "image", "required": True }], "outputs": [{ "name": "detections", "type": "json" }] } } }) ``` Only inline code (`metadata.code`, shown above) is supported today — uploading code as a separate file isn't wired up yet. `metadata.device` is optional (`"cpu"` or `"gpu"`) — see the note above. It's only valid on `custom-hosted` models; setting it on `custom-api` is rejected, since your own endpoint decides its own compute. If your `run()` function needs a checkpoint, upload it as a tar archive in two steps: request a signed upload URL, then confirm the upload. ```bash theme={null} # 1. Request a signed URL curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/mlmodels//artifacts/upload-urls" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"files": [{"path": "checkpoint.tar"}]}' # 2. PUT your file to the returned upload_url, then confirm: curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/mlmodels//artifacts/complete" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"files": [{"path": "checkpoint.tar"}], "primary_path": "checkpoint.tar"}' ``` Your `run()` function receives the extracted contents' directory as `artifacts_dir`. Same as any other model — direct call, Playground, or a workflow's **Call Model** node. The first run after registering may take longer while capacity is provisioned. ```python theme={null} result = cw.models.run(model.uuid, image_url="https://example.com/frame.jpg") ``` *** ## Passing a recording as input A model that analyzes a whole recorded clip (rather than a single live frame) declares a `video`-typed input in its `io_schema`, and the caller passes the recording's UUID: ```python theme={null} result = cw.api.run_mlmodel( model.uuid, recording_uuid="", # from GET /twins/{uuid}/recordings ) ``` Cyberwave resolves `recording_uuid` into a temporary signed URL for the underlying video file before calling your endpoint or `run()` function. Whole-clip calls typically take longer than a single-frame call — timeouts are extended automatically when a model declares a `video` input. *** ## Endpoint reference | Method | Path | Purpose | | -------- | ----------------------------------------------- | ------------------------------------------------- | | `POST` | `/api/v1/mlmodels` | Register a `custom-api` or `custom-hosted` model. | | `POST` | `/api/v1/mlmodels/{uuid}/credential` | Set (or replace) auth credentials. | | `DELETE` | `/api/v1/mlmodels/{uuid}/credential` | Remove stored credentials. | | `POST` | `/api/v1/mlmodels/{uuid}/test-call` | Run one validation call against your endpoint. | | `POST` | `/api/v1/mlmodels/{uuid}/artifacts/upload-urls` | Request signed URLs to upload weights. | | `POST` | `/api/v1/mlmodels/{uuid}/artifacts/complete` | Confirm an uploaded artifact. | | `POST` | `/api/v1/mlmodels/{uuid}/run` | Run the model. | ## Where to go next Model visibility, capabilities, and the catalog in general. Try any model — including your own — from an interactive UI. Full request/response reference for the model catalog endpoints. # Online controllers Source: https://docs.cyberwave.com/feature-reference/online-controllers Run custom code, random policies and trained RL checkpoints in a cloud controller node that drives a simulated or live robot over MQTT and WebRTC. ## Find controls in the Workbench Open **Workbench → Control** and select a twin to see its actions, control methods, controller settings and related workflows. **Manual inputs** lists saved input mappings and opens the existing keyboard or leader-arm editor. **Workflows & shortcuts** lists environment tasks; it is grey when no workflows exist. Shortcuts run only in their matching Simulation or Live mode. The detailed controller settings remain available, including model/camera configuration, code and motion sequences. Adding a different input may replace the twin’s primary controller; review that change before assigning it. A saved mapping does not confirm that its device is connected. Select an action to focus its controls. In catalog Control and Workbench, **Other controls** keeps existing **Manual inputs** and **Autonomy and logic** settings together when they are shared across actions. In Edit, expand **Controller & runtime settings** for the full controller detail; operating controls stay visible in Simulation and Live. Opening or switching actions does not change a saved assignment. For a configured IK service, open **End-effector → Autonomy and logic → Tool frame**. Select the tool's robot link and choose **Place working point** to show the 3D handles. **Finish placement** hides them. Expand **Exact offset** to enter position and rotation; position is in metres relative to the link. **Save** on the asset sets the default for newly added twins; Save in Workbench changes only that twin. The configured solver is retained. Saving does not move the robot or confirm collision-free operation. Use **Overview** to see the twin’s mappings, policies and related workflows together. SDK examples are available in the asset’s **Code** tab. Pin control guides, cameras or microphones to the **Overview** panel. Choose **Arrange** to show the handles and reorder them, save personal layouts, or—if you can edit the environment—save an environment default. Your personal layout takes precedence. A command-connection warning describes the connection used to send commands; it does not mean your keyboard is disconnected. Robot keys pause while you use the Overview toolbar. After closing **+ Pin** or the layout menu with the keyboard, Tab to **Resume keyboard controls** and press Enter or Space to return to robot input. Clicking outside either menu restores robot input unless you move into a text field or dialog. Changing a key or gamepad button preserves that command’s saved values. Review its parameters separately to change the amount or behavior; catalog defaults initialize new bindings. Commands such as adjustable lights need a value before saving. The mapping editor shows the configured parameter and its range; expand **Other parameters** to use a supported alternative. For **Navigate**, **End-effector** or **Joint targets**, choose **Open control panel** to pin the supported operator control. In Simulation or Live, switch to **Control**. Choose a target, or expand **Enter coordinates** / **Enter joint values**; checks run automatically and **Move** or **Go to point** remains unavailable until the target can run. Live movement may require confirmation. Expand **Live unavailable** to see why a control works in Simulation but needs driver support for Live. The same limitation appears once for controls grouped under a twin. A hardware limitation remains unavailable in both modes; unverified support must be checked in the catalog. Switching modes or opening this guidance does not send a command. Navigation needs a current localized pose. If localization is unavailable or stale, restore the selected mapping/localization service and its sensor input before retrying. A saved map with no observed free space cannot be used for localization: capture a new map with free-space tracing or choose another map. The map remains available for inspection. Saved poses, **Drive to home pose**, and workflow joint movements require declared controllable joints. Complete gripper poses may include coupled fingers when they agree with the driver joint. If an imported robot is rejected, review its actuation setup and joint limits in the catalog; movable geometry alone does not establish command support. For a spatial target, choose **Place target**, right-click a scene point and select **Set control target here**. Drag the marker to adjust its position, then choose **Done** to hide the handles. Expand **Enter coordinates** for world coordinates in metres. **Describe target** opens the [control agent](/ai/control-agent) for the selected twin; review its result before running it. Placing a target does not move the robot. Use **Arrange** to reorder pinned panels. A saved layout remembers the panel, not a destination or joint command. Missing robot capabilities remain unavailable even when a 3D model has movable joints. In **Attach target evidence**, saved task and model choices stay selected when the catalog refreshes. If one is unavailable, choose its replacement explicitly. Attaching a result does not run a model. For a perception action, **Workflow task** lists compatible environment workflows and available templates. Select a template, then choose **Use template in this environment** to create an inactive copy linked to the twin. This also works for an inherited template. Open **Edit model & inputs** to select its camera or other sensor sources; the catalog template stays unchanged. Missing setup appears beside the selected task. Saving the setup does not activate the workflow or confirm sensor availability. In Workbench, **Enable** starts the linked workflow’s triggers once its checks pass; **Pause** disables them. A blocker appears beside the task with **Edit model & inputs**. Cloud or Edge beside the model describes inference placement; Enabled does not confirm that results are arriving. ## What is an online controller? An **online controller** is a controller policy that runs in its **own controller-host cloud node** — separate from the simulation. The controller host communicates with a **plant** (the `cyberwave-sim` physics worker *or* a live robot) over MQTT and WebRTC. The plant only steps physics and publishes state; it never runs the controller logic in its own loop. This split is the defining property of online controllers: the control loop and the physics loop live in different processes, connected by a wire. Because that wire is the same whether the plant is a simulator or a real robot, an online controller can target either with no code changes. | | Plant (`cyberwave-sim` or live robot) | Controller host (cloud node) | | -------------------------- | ----------------------------------------- | ---------------------------------- | | **Role** | Steps physics / hardware, publishes state | Runs the controller policy | | **Communicates via** | MQTT joint state, WebRTC frames | MQTT joint commands, WebRTC frames | | **Runs the control loop?** | No | Yes | Cyberwave supports **basic mjlab** today — online controllers run against both basic MuJoCo and vectorized mjlab backends over the same wire. We're planning to release a richer Cyberwave mjlab extension with useful helpers in the future. ## Online controller types Three policy types run on the online-controller host path: A custom Python controller you write — a `control()` function or a stateful controller class — optionally carrying named model weights. A random policy, optionally shaped by weights. Useful for smoke-testing a plant or establishing a baseline. A trained RL checkpoint exported from an RL Task, evaluated closed-loop against the plant. Other controller policies — `teleop`, `navigation`, `motion`, and `mlmodel`/`vla` — do **not** use the online-controller host path. They run on their own command-triggered or cloud inference paths. ## How controllers are routed Routing is decided by the **explicit policy type plus a structured controller family** — never by keyword or name matching. When you start a run, the backend resolves the assigned policy and dispatches it to the matching controller host. | Online controller | Resolves by | Runtime view | | --------------------------- | -------------------------- | -------------------------- | | `code` (and code + weights) | `code` policy type | MuJoCo-shaped sim view | | `random` | structured `random` family | MuJoCo-shaped sim view | | `rltask` | structured RL-task family | `SimulationLike` interface | ## Runtime interfaces Each online controller interacts with its plant through a sim-shaped interface, so your controller code reads state and writes commands without knowing whether the plant is simulated or live. * **`code` and code + weights controllers** see a **MuJoCo-shaped sim view** — a familiar `sim.data` / `sim.model` surface for reading joint state and writing controls. * **`rltask` (RL) policies** use a **`SimulationLike`** interface — the same observation/action contract an RL policy expects during training. Keep these as conceptual contracts: your controller reads observations and writes actions each step; the host handles transport to and from the plant. ## Authoring code controllers Code controllers support two authoring modes. ### Function mode (default) Define a `control` function. The host calls it each control step. ```python theme={null} def control(sim, sim_time, artifacts=None): # Read state from the sim view, compute, and write controls. sim.data.ctrl[:] = 0.0 ``` * `sim` — the MuJoCo-shaped sim view (read state, write `ctrl`). * `sim_time` — current simulation time in seconds. * `artifacts` — a dict of named weights/files (present only for code + weights controllers). ### Class mode (`entrypoint_type="class"`) For stateful controllers that load weights once and keep state across steps, use class mode. The host instantiates the class once, then calls it each step. ```python theme={null} class Controller: def __init__(self, sim, artifacts=None): # Load weights, allocate buffers, set up state once. self.sim = sim def __call__(self, sim_time): # Called each control step. self.sim.data.ctrl[:] = 0.0 ``` Set `entrypoint_type="class"` on the policy to opt into class mode. Use it whenever your controller needs to load model weights or maintain internal state between steps. ## Named artifacts and weights A code + weights controller attaches one or more **named binary files** — typically `.pt`, `.onnx`, or `.safetensors`. Each artifact carries: | Field | Meaning | | ------------ | ------------------------------------------------------- | | **Filename** | The runtime key your code uses to look the artifact up. | | **Role** | Optional label describing what the artifact is. | | **Primary** | A flag marking the main artifact for the controller. | The artifacts reach your code differently per authoring mode: * **Function mode** — delivered as the third positional argument, the `artifacts` dict. * **Class mode** — delivered to `__init__` as the `artifacts` argument, so you can load them once. Class mode plus named artifacts is the canonical pattern for a trained policy: load the primary checkpoint in `__init__`, then run inference each step in `__call__`. ## Running a skill from the control agent In **Simulate → Agent**, describe the skill and any run limit, then select **Plan**. Check the selected robot, policy and limits before executing; start the required simulation first. The assistant follows the controller's current run status, and cancelling that action stops only that run. A completed run does not prove task success—check its policy evidence and Replay separately. The assistant keeps a trained skill's saved settings unless it exposes a supported command input. Use a **policy-step limit** to bound these runs; a duration alone is not currently supported. A robot accepting velocity commands does not mean every policy on that robot accepts speed or gait overrides. ## CPU vs GPU compute Controller policies that **carry a model** — `mlmodel`/`vla`, `random`, or code-with-weights — accept an inference `device`. This choice selects where the controller host runs inference and is **independent of the simulation's physics device**. | `device` | Where it runs | When to use | | ----------------- | ---------------- | ----------------------------------------------------------------- | | `cpu` *(default)* | A cheap CPU host | Lightweight inference; the default for any model-carrying policy. | | `gpu` | A GPU host | Heavier policy inference that benefits from a GPU. | Key rules: * **`cpu` is the default.** It runs on an inexpensive CPU host. * **The saved `device` is just the default.** You can override it per-run at deploy time without changing the saved policy. * **`device` is rejected for policies that carry no model** — for example a plain `code` controller or a `teleop` policy. Those have nothing to run inference on. The `device` choice is purely about controller inference. It does not affect which device the plant uses to step physics. ## Live mode Because the controller host talks to its plant purely over MQTT and WebRTC, the **same** `code`, `random`, or `rltask` controller can target a **live robot** plant instead of `cyberwave-sim` — with no controller code changes. The controller reads state and writes commands exactly as it does in simulation; only the plant on the other end of the wire changes. ## Simulation backends Online controllers run against two simulation backends over the same wire: * **Basic MuJoCo** — a single `MjModel` / `MjData` plant. * **Vectorized mjlab** — a manager-based, GPU-capable plant. Your controller does not need to know which backend the plant uses; the runtime interface is the same. ## Quick example Create a code controller policy, then run it against a twin. Create a `code` policy with your control function (or class). ```http theme={null} POST /api/v1/controller-policies ``` Execute the policy against a robot twin. The backend dispatches the controller to its host, which drives the plant. ```http theme={null} POST /api/v1/controller-policies/{uuid}/execute ``` Stop a single policy run, or stop every online controller in an environment at once. ```http theme={null} POST /api/v1/controller-policies/{uuid}/stop POST /api/v1/controller-policies/stop-environment-controllers ``` A minimal code controller body: ```python theme={null} def control(sim, sim_time, artifacts=None): # Hold all joints at zero command. sim.data.ctrl[:] = 0.0 ``` ### Deploy a trained RL policy An `rltask` controller is created by publishing a trained checkpoint, then assigned to a twin like any other controller. Using the OpenArm pick-up policy from the [RL task walkthrough](/feature-reference/rl-task-walkthrough): ```python theme={null} import requests from cyberwave import Cyberwave cw = Cyberwave() # 1. Publish a trained checkpoint as an rltask controller policy. publish = requests.post( f"{cw.config.base_url}/api/v1/rl-tasks//checkpoints//publish-controller", headers={"Authorization": f"Bearer {cw.config.api_key}"}, json={"controller_name": "openarm-pickup-policy"}, ) publish.raise_for_status() controller_uuid = publish.json()["controller_policy_uuid"] # 2. Assign it to the arm twin (first argument is the twin UUID). cw.twins.update("", controller_policy_uuid=controller_uuid) ``` Then **start a simulation** from the environment's **Simulate** tab in the dashboard — the backend resolves the assigned policy and dispatches it to its controller host automatically. See [Uploading Policies](/feature-reference/uploading-policies) for how the checkpoint and controller are produced. ## API reference | Method | Path | Purpose | | -------- | ---------------------------------------------------------- | ---------------------------------------------- | | `GET` | `/api/v1/controller-policies` | List controller policies. | | `POST` | `/api/v1/controller-policies` | Create a controller policy. | | `GET` | `/api/v1/controller-policies/{uuid}` | Get a controller policy. | | `PUT` | `/api/v1/controller-policies/{uuid}` | Update a policy, including the saved `device`. | | `DELETE` | `/api/v1/controller-policies/{uuid}` | Delete a controller policy. | | `POST` | `/api/v1/controller-policies/{uuid}/execute` | Run the policy on a twin. | | `POST` | `/api/v1/controller-policies/{uuid}/stop` | Stop a policy/twin run. | | `POST` | `/api/v1/controller-policies/stop-environment-controllers` | Stop all online controllers in an environment. | | `POST` | `/api/v1/controller-policies/{uuid}/clone` | Duplicate a controller policy. | | `GET` | `/api/v1/controller-policies/{uuid}/rl-task-provenance` | Get RL-task provenance for a policy. | ## Control setup In **Workbench / Control**, select a twin. **Overview** shows its configured inputs, policies and workflow-backed services together. Each saved service links to its action setup, including any missing inputs or changed references. Select an action to review **Autonomy and logic**, its input, and **Advanced settings**. **Other controls** retains the original shared settings. Related workflows appear in **Overview**. The selected model shows the kind of output it produces. **Relative depth** has no metric distances; **Metric depth** still needs camera calibration and a suitable mapping pipeline. A path predicted in an image is not a robot navigation route. Catalog services identify reusable **Workflow templates**; Workbench shows the state of the environment workflow. If a required workflow input comes from a disabled or removed node, Control shows the missing input. Use **Edit model & inputs** to restore or replace its source. Restoring the configuration does not start the workflow. In **Maps**, **Point projection** identifies a grid made from point-cloud observations. Unobserved cells remain unknown. **Legacy grid** preserves an older grid for inspection; review its source and calibration before navigation. Viewing these maps keeps their original downloads. **Waiting for first map** means the stream has not supplied a map image yet. **Maps** remains available in the right panel in Edit, Simulate and Live, including when no robot is selected. Select a robot to use its declared mapping service. Monitor keeps mapping controls read-only. Control requires edit access; in Simulate, start a simulation before starting a map. Saved maps remain viewable when the run stops. Generating a map from authored geometry remains in Edit. For a configured mapping service, **Maps** shows the robot’s service under **Autonomy and logic** and offers its supported map types. Missing sensor setup blocks **Start mapping**. **Legacy sensor mapping** retains an older configuration for review. Requesting mapping does not confirm that its runtime is connected or that a map has arrived. **Map details** shows the source robot, status, resolution and recorded service. Expand **Technical details** to inspect or copy the complete record. If a simulation ends before mapping finishes, the map is marked **Interrupted** and received snapshots are retained. A saved map still needs coverage and alignment checks before use for navigation. Catalog **Control** has three sections: **Control services**, **Hardware drivers** and **Catalog preview**. Control services uses the same action organization as Workbench. Editors can change setup rules under an action’s **Advanced settings**; hardware capabilities remain in **Capabilities**. Adding a twin copies saved asset action settings into that twin. Workbench edits stay local to it; the reusable input preset and asset defaults are unchanged. **From asset defaults** and **Customized for this twin** identify the saved scope. These action settings do not activate inputs yet. Use **Add input** to select an existing preset. Supported joint keys appear **From preset**. **Edit keys** customizes the action; **Reset to preset** removes that customization. Clearing every key keeps the action empty until you reset or map new keys. The reusable preset is unchanged. During editing, expand **Current input setup** to inspect the existing controls. From **Overview**, **Edit mapping** opens that action’s input settings directly. You can collapse the settings without losing unsaved changes. Read-only users can **View mapping**. For a standard command keyboard, **Use standard keys** fills supported keys for the selected action. Review them, then **Save**. The same keyboard can serve Drive, Camera and Lights with separate mappings. Existing custom keys are retained; use **Edit keys** to add commands that need your own values or choices. **Save** stores your action settings without starting a robot. The selected service appears under **Autonomy and logic**; its configuration details stay beside the selector. Use the operating panels in Workbench to control a robot. Saving does not activate inputs; pairing, calibration and runtime readiness are checked on the twin. **Direct control** means the action uses its configured manual inputs without an action policy. When compatible policies exist, you can select one or return to Direct control while retaining your input mappings. Actions that require a policy still show **Not configured** until one is selected. This choice does not certify that the simulator or hardware is ready. The operating panels can list supported joints even before the 3D model loads. Enter targets in the displayed units and review them before moving. Changing a target requires a new review; motion requires a ready execution route. Control setup remains configuration only. For an immediate simulation move, **Queued** means the command was sent, not that the robot reached its target. Updated simulators report progress while running and confirm completion from measured joint positions. Older simulators may report only when the simulation ends. A pending status alone is not a reason to repeat the move. Publishing failures are reported as errors. When a keyboard command needs values, its mapping editor shows a **Parameters** step after you choose a key. For example, a configured gripper can offer **grip**, **release** or **reset**. Complete required values before saving. Reopening the same preset in Catalog or Workbench preserves the saved parameters. Editing parameters requires saving them; **Assign as-is** uses only an unchanged, complete preset. Saving a mapping does not verify a connected device or execute its command. In **Workbench / Control**, **Add action** opens the same picker as the catalog. Choose a declared action to configure its manual inputs and logic inline. Configuration pages do not start a robot or embed a test panel. Additional legacy setup paths remain under **More actions**. Opening setup does not start control. ## Where to go next Train and export RL policies to run as `rltask` online controllers. Bring your own code and weights as a controller policy. How the simulation plant steps physics and publishes state. In an action’s **Advanced settings**, use **Show operator panel** to hide its on-screen target control. Catalog settings apply when adding new twins; Workbench settings apply to the selected twin. A saved pin stays in your layout with a hidden-state message. SDK, agent and workflow access are unchanged. Existing shared keyboard guides are managed separately. In **Workbench → Control → Overview**, use **Edit mapping** to change supported keyboard keys for that twin. Joint and command keyboards reuse their existing editors. Command-key edits preserve the saved movement, camera and lighting commands and their values. Saving preserves the shared preset and other twins’ mappings. If the input or keys changed elsewhere, reload before saving. For a robot with attached twins, select each twin’s saved keyboard mappings in **Workbench → Control → Overview**. Distinct keys can stay selected together. **Pause input** affects only the selected twin; conflicting keys explain what to change before activation. **Restore previous environment inputs** returns all twins to their previous input assignments. Multiple gamepad inputs cannot yet be selected together. With driver-based keyboard controls, switching windows pauses held input. After returning or restoring the command connection, release held keys and press again. For a calibrated leader-arm preset, use **Map joints** to pair each servo with a robot joint. **Arrange mapping** enables drag placement; **Done** hides it. Optional aliases stay under **Advanced**. Catalog edits update the shared preset; calibrate the connected leader on a twin before operating. In Workbench, **Use input** assigns an unchanged preset; **Save & use input** saves mapping edits and assigns it. Those edits affect every twin using the preset. Existing legacy presets keep their current editor. New input choices follow the selected action. A saved input that conflicts with that action shows **Deprecated mapping**. Use **Review migration** to remove or replace it, then **Save**. The shared preset is retained. **Needs mapping** means setup is incomplete; saving does not verify a connected device. Keyboard and gamepad mappings stay visible while a physics simulation starts or is stopped. Controls pause until the simulator is ready; Playground controls remain available without starting a backend simulation. The compact joint guide shows the last commanded **Target** and **Δ**, the difference from the reported position. **No feedback** or **Feedback stale** means it cannot confirm the current position. In Playground, the readout follows the scene; a physics simulation needs its own feedback. Angle units can change without enabling control; linear joints remain in metres. Pinned navigation and joint target panels follow the same readiness state. You can enter targets while waiting; they are checked automatically when the simulator is ready. Checking a target does not move the robot. # RL task scene sensors Source: https://docs.cyberwave.com/feature-reference/rl-task-scene-sensors Configure cameras, depth cameras, and contact sensors on RL task scene entities The RL Composer's **Sensors** subsection lets you opt schema-defined cameras into the mjlab `SceneCfg.sensors` tuple and author MuJoCo contact sensors. Each entry lives on a single `RLTaskSceneEntity` row and is persisted as a JSON object on the entity's `sensors` field. The backend aggregates every entity's `sensors` list when it regenerates `scene_cfg.py`, so a contact sensor on the `robot` entity referencing the `cube` entity ends up as one `ContactSensorCfg` in the SceneCfg with both `ContactMatch` blocks pointed at the right entities. ## Supported sensor types * **Camera** (RGB / depth) — schema-derived. One UI card per *physical* device, even when the schema lists separate `color_camera` + `depth_camera` entries: Cyberwave groups them by the stripped parent-link key so a single Orbbec Gemini surfaces one logical entry with `RGB` and `Depth` toggles. The composer reads `Twin.universal_schema.sensors` for the host twin *and* every twin docked to it. * **Contact** — user-authored. Each row maps directly to one `mjlab.sensor.ContactSensorCfg(primary=ContactMatch(...), secondary=ContactMatch(...) | None, ...)`. The primary side defaults to the host entity; the secondary side picks any sibling RL task scene entity by name (or stays empty for an "any-contact" detector). ## Persisted JSON shape The `RLTaskSceneEntity.sensors` field stores one of two row shapes. Camera (one row per logical device): ```json theme={null} { "type": "camera", "name": "wrist_cam", "source_twin_uuid": "abc-…", "schema_sensor_names": ["color_camera", "depth_camera"], "data_types": ["rgb", "depth"], "bind_mjcf_camera": "depth_camera", "width": 640, "height": 480, "fovy": 65.0 } ``` Contact: ```json theme={null} { "type": "contact", "name": "left_finger_cube", "primary": { "mode": "subtree", "pattern": "openarm_left_finger1", "exclude": [] }, "secondary": { "entity": "cube", "mode": "subtree", "pattern": "cube" }, "fields": ["found", "force"], "reduce": "maxforce", "num_slots": 1, "history_length": 0 } ``` ## Codegen mapping `scene_codegen.py` walks every entity's `sensors` list and emits one `ContactSensorCfg` per contact-sensor row into `SceneCfg.sensors=(...)`. Camera sensors are **not** emitted as `CameraSensorCfg` entries in `SceneCfg.sensors`; instead, the packager preserves camera metadata (MJCF camera name, width, height, data\_types) in `scene_bindings.CAMERA_SENSORS`. At runtime, `env_cfg.py` wires each camera observation term via `standard_camera_resolver(camera_sensors=bindings.CAMERA_SENSORS, ...)` from `task_export.standard_resolvers`, which routes depth terms to `mdp.observations.DepthCameraObservationCfg` and RGB terms to `mdp.observations.ColorCameraObservationCfg`. The merged MJCF prefixes every camera body with `/__`, so a camera bound to a docked twin stays addressable inside the host entity's subtree. When no entity carries any sensor the codegen falls back to the no-op default `sensors=()` and drops the `mjlab.sensor` import. ## Docked-twin caveat (contact subtrees) When a host twin has docked twins (e.g. a wrist camera attached to a robot arm), the merged MJCF prefixes every docked body with `__`. A contact sensor with `mode="subtree"` on the host entity therefore *also* matches bodies inside docked subtrees unless you exclude them explicitly. The composer surfaces an amber warning under each docked twin with a one-click "Add to exclude" button that injects the suggested regex (`^__.*$`) into the primary `exclude` list. ## SDK The Python SDK exposes `make_camera_sensor(...)` and `make_contact_sensor(...)` convenience builders alongside a new `sensors=` keyword on `assign_articulation_entity` / `assign_rigid_entity`. See `cyberwave-sdks/cyberwave-python/cyberwave/rl_tasks.py` for the full signatures. # RL task walkthrough Source: https://docs.cyberwave.com/feature-reference/rl-task-walkthrough Build an RL task end to end in Python: scaffold, compose an OpenArm pick-up scene, author the MDP, export, train, and deploy as an online controller. This walkthrough builds one concrete task from an empty workspace to a deployed policy: an **OpenArm learning to pick up a cube off a table**, with a wrist depth camera. It uses the Python SDK throughout so you can run it as a reproducible setup script. It ties together the four RL surfaces: The entity and editor tabs this script automates. Wiring the wrist depth camera and contact sensors. Upload the trained checkpoint and run it. Deploy the policy against a simulated or live robot. ## The scene Four twins make up the task. Each maps to one mjlab scene entity: | Twin | Catalog asset | Role | Base | | ------------- | --------------------------------- | ------------------------------------- | ------ | | `openarm` | `enactic/openarm` | The arm — the `robot` articulation | Fixed | | `support_box` | `cyberwave/generic_cube` (scaled) | The table | Fixed | | `red_cube` | `cyberwave/generic_cube` (scaled) | The object to pick up | Free | | `wrist_cam` | `intel/realsensed455` | Wrist depth camera, docked to the arm | Docked | The catalog assets (`enactic/openarm`, `cyberwave/generic_cube`, `intel/realsensed455`) must already exist in your workspace's catalog. On a local stack they are added by `make seed`. ## Prerequisites ```bash theme={null} pip install cyberwave export CYBERWAVE_BASE_URL=http://localhost:8000 export CYBERWAVE_API_KEY= # the SDK reads this; `cyberwave login` does not configure the SDK ``` ```python theme={null} from cyberwave import Cyberwave from cyberwave.placement import GENERIC_CUBE_BOUNDS from cyberwave.rl_tasks import ( RLTaskClient, make_action_spec, make_position_delta_action, make_observation_spec, make_joint_observation, make_previous_action_observation, make_camera_observation, make_camera_sensor, make_default_ppo_rlmodule_config, ) cw = Cyberwave() # reads CYBERWAVE_BASE_URL + CYBERWAVE_API_KEY rl = RLTaskClient(cw) ``` ## Step 1 — Scaffold workspace, project, and environment ```python theme={null} # Use your first workspace (or look one up by name). workspace = cw.workspaces.list()[0] project = cw.projects.create(name="RL Tasks Demo", workspace_id=str(workspace.uuid)) env = cw.environments.create( name="openarm_pickup", project_id=str(project.uuid), description="OpenArm pick-up RL task", ) print("environment:", env.uuid) ``` ## Step 2 — Compose the scene Add the four twins to the environment. The arm is fixed-base, the cube is free, and the camera is docked to the arm's wrist link. ```python theme={null} scene = cw.get_scene(str(env.uuid)) # The arm: a fixed-base articulation placed by its link origin. arm = scene.add_twin( asset_key="enactic/openarm", name="openarm", position=[0.0, 0.0, 0.48], orientation=[0.0, 0.0, 0.0, 1.0], fixed_base=True, ) # Table + cube: generic cubes scaled to real sizes. add_twin_centered # authors by visual centre + dimensions (metres), so you don't convert # to the asset's link origin by hand. table = scene.add_twin_centered( asset_key="cyberwave/generic_cube", name="support_box", center=(0.525, 0.0, 0.67), dimensions=(0.70, 0.80, 0.10), asset_bounds=GENERIC_CUBE_BOUNDS, fixed_base=True, ) cube = scene.add_twin_centered( asset_key="cyberwave/generic_cube", name="red_cube", center=(0.375, 0.14, 0.74), dimensions=(0.04, 0.04, 0.04), asset_bounds=GENERIC_CUBE_BOUNDS, fixed_base=False, ) # The wrist camera, docked to the arm's wrist link. wrist = scene.add_twin( asset_key="intel/realsensed455", name="wrist_cam", position=[0.0, 0.0, 0.0], orientation=[0.0, 0.0, 0.0, 1.0], fixed_base=False, ) scene.dock( child_twin=wrist, parent_twin=arm, link_name="openarm_left_link7", offset_position=[0.06, -0.055, 0.13], offset_rotation=[0.25, 0.25, 0.65, 0.65], # xyzw ) ``` `add_twin` places a twin by its **link origin**; `add_twin_centered` places it by its **visual centre** and scales it to `dimensions` (metres) using the asset's `asset_bounds`. Use the centred helper whenever you scale a generic primitive to a real-world size. ## Step 3 — Create the RL task Link the task to the environment and declare the entrypoint files Cyberwave will generate or expect. ```python theme={null} import requests resp = requests.post( f"{cw.config.base_url}/api/v1/rl-tasks", headers={"Authorization": f"Bearer {cw.config.api_key}"}, json={ "name": "OpenArm pick-up demo", "workspace_uuid": str(workspace.uuid), "project_uuid": str(project.uuid), "environment_uuid": str(env.uuid), "scene_cfg_path": "scene_cfg.py", "env_cfg_path": "env_cfg.py", "env_cfg_factory": "make_env_cfg", "rl_cfg_path": "rl_cfg.py", "rl_cfg_factory": "make_rl_cfg", "registry_path": "registry.py", "visibility": "private", }, ) resp.raise_for_status() task_uuid = resp.json()["uuid"] print("task:", task_uuid) ``` ## Step 4 — Assign scene entities Tell Cyberwave which twin is which mjlab entity, whether it is articulated, and which actuators the arm exposes. The wrist depth camera is attached as a sensor on the `robot` entity. ```python theme={null} ARM_JOINTS = [r".*__openarm_left_joint[1-7]$", r".*__openarm_left_finger_joint[12]$"] # Wrist depth camera (32x32 depth, sourced from the docked D455 twin). wrist_cam_sensor = make_camera_sensor( "wrist_cam", source_twin_uuid=str(wrist.uuid), schema_sensor_names=["color_camera", "depth_camera"], data_types=["depth"], bind_mjcf_camera="depth_camera", width=32, height=32, fovy=60.0, min_depth=0.05, max_depth=0.40, ) rl.assign_articulation_entity( task_uuid, twin_uuid=str(arm.uuid), name="robot", base_type="fixed", actuators=[{"type": "xml_position", "target_names_expr": ARM_JOINTS}], sensors=[wrist_cam_sensor], ) rl.assign_rigid_entity(task_uuid, twin_uuid=str(table.uuid), name="support_box", base_type="fixed") rl.assign_rigid_entity(task_uuid, twin_uuid=str(cube.uuid), name="cube", base_type="free") ``` Call `rl.get_orchestration_hints(task_uuid)` to confirm the `robot` entity, its actuated joint names, and the camera sensor name (here `robot__wrist_cam`) before authoring specs against them. ## Step 5 — Author actions, observations, and the network ```python theme={null} # Actions: one position-delta term driving the arm + fingers. rl.set_action_spec(task_uuid, make_action_spec([ make_position_delta_action( "joint_delta", entity="robot", target_names_expr=ARM_JOINTS, scale=0.04, ), ])) # Observations: a single "policy" group shared by actor and critic. rl.set_observation_spec(task_uuid, make_observation_spec({"policy": [ make_joint_observation("joint_pos", kind="position", entity="robot", target_names_expr=ARM_JOINTS), make_joint_observation("joint_vel", kind="velocity", entity="robot", target_names_expr=ARM_JOINTS), make_previous_action_observation("actions"), make_camera_observation("wrist_depth", sensor="robot__wrist_cam", data_type="depth"), ]})) # RL config: PPO with the default shared-MLP network. rl.set_rl_config_spec(task_uuid, make_default_ppo_rlmodule_config()) ``` This walkthrough uses PPO with a small shared MLP to stay readable. For a vision policy you would author a CNN backbone that consumes the `wrist_depth` term — the network builder supports graph topologies for exactly this. See the [Network builder](/feature-reference/rl-tasks#network-builder) section. ## Step 6 — Generate files and export ```python theme={null} # Build the Cyberwave-generated scene_cfg.py + spec-derived files from the # linked environment and the specs you just authored. rl.regenerate_scene_cfg(task_uuid) # Download the runnable plugin ZIP. import requests zip_resp = requests.get( f"{cw.config.base_url}/api/v1/rl-tasks/{task_uuid}/export.zip", headers={"Authorization": f"Bearer {cw.config.api_key}"}, ) with open("openarm_pickup.zip", "wb") as fh: fh.write(zip_resp.content) ``` Your task-local Python — the reward function, resets, and terminations — lives in the user-written `env_cfg.py` inside the export. Cyberwave generates everything else (`scene_cfg.py`, `scene_bindings.py`, the spec wrappers, the MuJoCo assets). ## Step 7 — Train Drop the exported folder into `cyberwave-rl/tasks/` and train it like any other task: ```bash theme={null} unzip openarm_pickup.zip -d cyberwave-rl/tasks/openarm_pickup cd cyberwave-rl make start make run_cfg arg_overrides="--task=openarm_pickup" ``` Training writes checkpoints to `logs///checkpoints/`. The best one is typically `best_agent.pt`. ## Step 8 — Upload the trained policy ```python theme={null} checkpoint = rl.upload_checkpoint( task_uuid, "cyberwave-rl/logs/openarm_pickup/run-1/checkpoints/best_agent.pt", name="best_agent", ) checkpoint_uuid = checkpoint["uuid"] ``` See [Uploading Policies](/feature-reference/uploading-policies) for the external-URL alternative and upload limits. ## Step 9 — Deploy the policy Publish the checkpoint as an `rltask` online controller, then assign it to the arm twin and run it. The controller runs in its own controller host and drives the plant over MQTT, so the same policy works against a simulated or a live OpenArm. ```python theme={null} import requests publish = requests.post( f"{cw.config.base_url}/api/v1/rl-tasks/{task_uuid}/checkpoints/{checkpoint_uuid}/publish-controller", headers={"Authorization": f"Bearer {cw.config.api_key}"}, json={"controller_name": "openarm-pickup-policy"}, ) publish.raise_for_status() controller_uuid = publish.json()["controller_policy_uuid"] ``` Now assign `controller_uuid` to the `openarm` twin and start a simulation — see [Online controllers](/feature-reference/online-controllers) for assigning and running it, including the CPU/GPU compute choice. Alternatively, run a quick cloud inference loop without publishing a controller: ```python theme={null} run = rl.launch_inference( task_uuid, checkpoint_uuid=checkpoint_uuid, twin_uuid=str(arm.uuid), max_steps=1000, control_rate_hz=50, ) ``` ## What you authored vs what Cyberwave generated | You author (user-written) | Cyberwave generates | | ------------------------------------------------------- | ---------------------------------------------------- | | Reward, reset, and termination logic in `env_cfg.py` | `scene_cfg.py` from the linked environment | | Custom observation functions | `scene_bindings.py`, `actions.py`, `observations.py` | | The trained checkpoint | The strict task spec + MuJoCo scene assets | | Scene/action/observation/RL choices (via SDK or editor) | The runtime adapters and export ZIP | ## Where to go next Full reference for the editor tabs and export contract. Checkpoint upload, publish, and inference in depth. Run the deployed policy against a simulated or live robot. # RL tasks Source: https://docs.cyberwave.com/feature-reference/rl-tasks Package a Cyberwave environment plus your MDP and RL code as an mjlab/skrl task: author actions, observations and a network, then export a ZIP. An **RL Task** is a workspace-scoped, optionally environment-linked entity that packages a runnable reinforcement-learning plugin. Cyberwave generates the **SceneCfg** from a linked environment — the same MuJoCo scene used everywhere else in the platform — and you bring the rest of the MDP and RL code as an arbitrary tree of source files. Exporting an RL task produces a ZIP that drops directly into `cyberwave-rl/tasks//`, where the existing registry discovers it and `make run_cfg` runs it like any other task. Cyberwave currently supports **basic mjlab**: exported tasks are mjlab-compatible (scene config, action and observation terms, skrl training). We're planning to release a richer Cyberwave mjlab extension with useful helpers in the future. ## Why a separate entity? RL tasks are deliberately kept independent of [Environments](/overview/features/environment). Deleting an environment **detaches** any linked RL tasks (sets `environment` to none) instead of cascading the delete, so a task keeps its source tree even after the world it was originally trained against is gone. This matches how researchers actually iterate: the SceneCfg is a moving target, while the reward, action, and observation specs are the long-lived artefacts. ## Lifecycle You can also describe a robot task from the dashboard or the environment editor's **Agent** tab. Type `@` (or choose **Tag asset or scene object**) to select an existing scene object or a catalog asset by name/full slug. Tagging adds context; it does not create an instance or start training. The assistant can look for a compatible policy or prepare a training proposal when the task is supported. Review and confirm training separately from binding or running its result. The same training card appears in chat and **Policies**, showing reported epochs, episodes or transitions as they advance. These counts are progress, not a success score. **Scene built on export** means the configured scene entities will generate the scene when you export; you do not need to save a generated scene file first. **Scene source saved** identifies a saved source, not a compilation or evaluation result. If the editor reports **Scene setup needed**, add scene entities or use **Scene entities → Regenerate generated files**, then prepare a fresh training request when its inputs change. Use **Cancel training** on that card to review and cancel only its active attempt. Cancellation prevents a new result from registering; worker shutdown can still be in progress. Existing policies and recordings remain unchanged. After failure or cancellation, **Prepare a new attempt** opens a fresh proposal using the previous settings. Review and confirm it before training starts. If confirmation reports changed inputs, or the proposal has expired, choose **Prepare a fresh proposal**. Review the current task and settings again; the rejected or expired proposal does not start training. In **Live** and **Simulation**, open **Process** from the strip below the scene to follow workflow runs and their recorded named steps in the central workspace. The right panel stays available for the agent. Process is read-only, works in Monitor mode, and does not verify physical task success. It is hidden in Edit and Replay. Create an RL task from `/rl-tasks`, or from **File → Export → Create RL task from this environment** in the environment editor. Import an existing task ZIP (for example an in-tree task from `cyberwave-rl/tasks/`) to seed the source tree, or write files directly in the **Files** tab. Set the entrypoint paths — `scene_cfg_path`, `env_cfg_path` / `env_cfg_factory`, `rl_cfg_path` / `rl_cfg_factory`, and an optional `registry_path`. Cyberwave never forces a particular `from … import …` statement; the import wiring is yours. Regenerate the Cyberwave-generated SceneCfg module from the linked environment. This also rewrites the spec-derived files (`scene_bindings.py`, `actions.py`, `observations.py`, `task_export/`, and the strict task spec). Download the ZIP and drop the folder into `cyberwave-rl/tasks/`. Run it with `make run_cfg arg_overrides="--task="` exactly like the in-tree examples. Edit locally, then re-import the same folder back into Cyberwave to keep the editor in sync. The editor stays authoritative for Cyberwave-generated files. ## Editor tabs The RL task editor is organized into tabs that map onto the export contract: | Tab | What it authors | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Overview** | Task metadata, linked environment, and entrypoint paths. | | **Scene entities** | The articulation entities, their simulation actuators, cameras, and contact sensors. See [RL task scene sensors](/feature-reference/rl-task-scene-sensors). | | **Actions** | The policy-controlled action terms and their control-mode presets. | | **Observations** | Grouped observation terms for the policy and critic heads. | | **RL config** | skrl backend, algorithm, graph-based network builder, and trainer parameters. | | **Files** | The full source tree, including read-only Cyberwave-generated files. | | **Runtime** | Runtime target, accelerator, bundle version, and "Train locally" snippets. | | **Policies** | Upload trained checkpoints, publish controllers, and run inference. | For a task configured for **CPU**, scene export preserves authored mesh collisions supported by native MuJoCo. **GPU** exports still require primitive colliders or an appropriate simplified collision variant. Selecting CPU does not make arbitrary training code CPU-compatible; the task must also provide a compatible training implementation. ### Reviewing policy evidence **Training requests** shows the current training phase and reported progress in both the task and assistant conversation. When a task reports curriculum stages, the same card shows its current stage and recent training-stage success rate. That rate is not the final held-out evaluation; missing results remain unreported. In **Policies**, select a checkpoint and open **Evaluation evidence** to inspect episode outcomes and available Replay links. **Deployment reports** separately show reported checks from completed simulation deployments, including failures. Tasks with confirmed deployment checks can report these automatically; the report identifies whether it came from the controller or a task writer. Missing recordings or checks are not a successful result. Check **Final task outcome maintained** as well as intermediate stages: reaching the goal briefly is not sustained success. **Not reported** means that outcome is unavailable, not that it passed. These reports are not held-out evaluations or hardware approval. Neither viewing evidence nor finishing training automatically binds or publishes a policy. An evaluated teaching result offers **Use on this robot** directly. It creates a private controller if needed and assigns it without starting motion; replacing an existing controller requires confirmation. **Publish to catalog** is separate and does not require assigning the policy to a robot first. Replay displays only recorded channels: object motion appears when the episode includes it; older joint-only recordings do not demonstrate object movement. Policy evidence Replay links frame the recorded robot on entry. You can still orbit, zoom, play and scrub the timeline; this does not start a controller. ## Author from Python (SDK) Everything the editor tabs produce can also be authored from the Python SDK — useful for reproducible setup scripts. The `RLTaskClient` covers every tab via its `set_*_spec` methods, so a script and the dashboard produce the same specs. The Actions, Observations, and RL config tabs also ship `make_*` builder helpers; the command tabs are authored as plain dicts passed to `set_training_command_spec` / `set_inference_command_spec` (see step 4b below). The example below is the **OpenArm pick-up** task: a fixed-base arm, a table, a free-floating cube, and a wrist depth camera. It is the same scene used in the full [RL task walkthrough](/feature-reference/rl-task-walkthrough), trimmed to the essentials. ```python theme={null} from cyberwave import Cyberwave from cyberwave.rl_tasks import ( RLTaskClient, make_action_spec, make_position_delta_action, make_observation_spec, make_joint_observation, make_previous_action_observation, make_default_ppo_rlmodule_config, ) cw = Cyberwave() # reads CYBERWAVE_BASE_URL + CYBERWAVE_API_KEY rl = RLTaskClient(cw) task_uuid = "" # created via POST /api/v1/rl-tasks # Match the arm + finger joints (twin-namespaced at runtime). ARM_JOINTS = [r".*__openarm_left_joint[1-7]$", r".*__openarm_left_finger_joint[12]$"] # 1. Scene entities: which twin is which mjlab entity. rl.assign_articulation_entity( task_uuid, twin_uuid="", name="robot", base_type="fixed", actuators=[{"type": "xml_position", "target_names_expr": ARM_JOINTS}], ) rl.assign_rigid_entity(task_uuid, twin_uuid="", name="support_box", base_type="fixed") rl.assign_rigid_entity(task_uuid, twin_uuid="", name="cube", base_type="free") # 2. Actions: one position-delta term driving the arm + fingers. rl.set_action_spec(task_uuid, make_action_spec([ make_position_delta_action("joint_delta", entity="robot", target_names_expr=ARM_JOINTS, scale=0.04), ])) # 3. Observations: a single "policy" group the actor and critic share. rl.set_observation_spec(task_uuid, make_observation_spec({"policy": [ make_joint_observation("joint_pos", kind="position", entity="robot", target_names_expr=ARM_JOINTS), make_joint_observation("joint_vel", kind="velocity", entity="robot", target_names_expr=ARM_JOINTS), make_previous_action_observation("actions"), ]})) # 4. RL config: PPO with the default shared-MLP network. rl.set_rl_config_spec(task_uuid, make_default_ppo_rlmodule_config()) # 4b. (Optional) Command specs: a target generator your observations read. # Opt-in and split by lifecycle — tasks with no command fall back to a # null manager. The TRAINING spec drives mjlab's CommandManager (sampled # goals, resampled each window); the INFERENCE spec drives the live/ # inference command surface (externally supplied targets). # A code-backed term names its uploaded source module by dotted path # (``commands.viewpoint`` → ``commands/viewpoint.py``) and the class it binds. rl.set_training_command_spec(task_uuid, { "schema_version": 1, "commands": [{ "name": "viewpoint", "type": "custom", "module": "commands.viewpoint", "symbol": "ViewpointCommandCfg", "resampling_time_range": [4.0, 4.0], }], }) rl.set_inference_command_spec(task_uuid, { "schema_version": 1, "commands": [{ "name": "viewpoint", "type": "custom", "module": "commands.viewpoint", "symbol": "ViewpointCommandCfg", "payload_schema": {"target_position": "vec3"}, "source": {"kind": "mqtt"}, }], }) # 5. Regenerate the Cyberwave-generated files from the specs + linked environment. rl.regenerate_scene_cfg(task_uuid) ``` `rl.get_orchestration_hints(task_uuid)` returns the scene-derived dropdown data (articulated entities, actuator groups, actuated vs passive joint names, available sensors) the editor uses to populate its pickers — call it first to discover the exact entity and joint names before authoring specs. For the complete version — scaffolding the workspace, environment, and twins, wiring a wrist depth camera and contact sensors, training, and deploying the policy — follow the [RL task walkthrough](/feature-reference/rl-task-walkthrough). ## Actions ### Task input is not robot output A goal or requested walking speed is an **input to a policy**. The policy's actions are its **output to the robot or another controller**. These are separate contracts: a walking policy can accept speed and produce joint targets; a navigation policy can produce body velocities for an onboard controller whose actuators are not accessible. Match both contracts to the selected runtime. Simulation actuators in a robot model do not prove that its physical driver exposes them. Cyberwave's shared adapter has a simulation-only body-velocity output port. For an explicitly authored aerial policy, controller startup checks its frozen interface against the lower controller observed in the running simulator. Unsupported or mismatched interfaces are rejected. Do not treat an evaluated checkpoint or a URDF as hardware readiness. The **Velocity** preset below means joint velocity, not base/drone velocity. Keep incompatible outputs explicit instead of converting them silently. Authored command-level flight tasks reuse custom action/observation terms and the existing asynchronous training adapter. Their lower controller, output units, frame, limits and cadence must match the training version. Changing that controller requires a fresh task version and evaluation. This adapter support does not yet establish a verified end-to-end drone deployment in the dashboard; inspect actual deployment acceptance and Replay separately from training results. Flight checks use measured robot pose and velocity, without requiring a fake joint-state stream. They require the goal to remain achieved, not merely be crossed once. A missing root feed, a different flight controller or unexplained applied forces makes the result fail. These checks are implementation support; end-to-end drone dashboard verification is still pending. ### Joint action presets Action terms are authored from five control-mode presets: | Preset | Spec value | Formula | Requires actuator | | --------------------------- | ------------------------- | ---------------------------------------------------------------------------- | -------------------------------- | | **Position delta** | `position_delta` | `target = q_now + baseline_delta + action × scale` | `xml_position` | | **Smoothed position delta** | `smoothed_position_delta` | same as `position_delta`, delta ramped linearly over the decimation substeps | `xml_position` | | **Position target** | `position` | `target = action × scale + offset` (anchored at joint home) | `xml_position` | | **Velocity** | `velocity` | `target = action × scale + offset` | `xml_velocity` or `xml_position` | | **Effort / torque** | `effort` | `target = action × scale + offset` | `xml_motor` | `position`, `velocity`, and `effort` mirror the Isaac Lab / mjlab `JointPositionActionCfg` / `JointVelocityActionCfg` / `JointEffortActionCfg` math one-to-one — exactly the `target = action × scale + offset` that mjlab implements in `BaseAction.process_actions`. `position_delta` is Cyberwave's own preset: `baseline_delta` is an explicit per-step bias baked into the target, so an action of zero can drift the joints toward a goal pose. `smoothed_position_delta` is the same delta, but spread evenly across the policy step's physics substeps for a smoother velocity profile. A single **Use default joint offset** checkbox mirrors mjlab's `use_default_offset`: when on, mjlab replaces `offset` with each joint's `default_joint_pos` (or `default_joint_vel`) at runtime so action zero returns the joint to its home pose. Every numeric field (`scale`, `offset`, `baseline_delta`) has a **Per joint** toggle that switches it between a uniform scalar and a `{joint_name: value}` mapping. The backend rejects per-joint keys that aren't in the action's selected joints, so typos surface at save time. Legacy symbolic offsets (`"default"`, `"zero"`, `"none"`) keep round-tripping unchanged. The **Scene** tab is where you enable **simulation actuators** for an entity (which `Xml*ActuatorCfg` wrapper drives each joint); the **Actions** tab is where you pick the policy-controlled subset of those actuators. Each action row renders a schema-backed joint table (Joint, Control type, Position min/max, Max velocity, Max torque/force, KP, KD, Selected) with **Select all** / **Clear**. Passive joints, spring-only actuators, and joints driven by an incompatible wrapper appear greyed out with a hint. Incompatible presets are hidden rather than shown disabled. Concrete joint names are stored in `target_names_expr`; a collapsed **Advanced — custom regex** disclosure lets imported or legacy specs keep regex patterns. **One action per joint.** Every `(entity, joint)` pair can be assigned to at most one action term — the policy emits a single value per actuated DOF. The Actions tab enforces this in three places: joints already controlled by another row render disabled with an "owned by …" pill; **Select all** only picks unclaimed joints; and `PUT /api/v1/rl-tasks/{uuid}/actions` rejects overlapping payloads with an error naming both action names and a sample of overlapping joints. To split a robot across two terms (for example arm + gripper), give each term a disjoint subset of joints. ## Observations Observation terms are organized into named groups (`policy`, `critic`, …) and drawn from a catalog: | Term | Description | | ----------------- | -------------------------------------------------------------------------------------------------------- | | `joint_position` | Joint positions. | | `joint_velocity` | Joint velocities. | | `joint_effort` | Joint efforts / torques. | | `link_position` | Body position; pick among `x` / `y` / `z` components. | | `link_pose` | Body pose: `x` / `y` / `z` plus a single `quat` token keeping the full `(qw, qx, qy, qz)` tuple grouped. | | `link_velocity` | Body twist: `x` / `y` / `z` linear plus `rx` / `ry` / `rz` angular. | | `camera` | Depth or color from a sensor configured on a scene entity. | | `previous_action` | The previous action tensor. | | `custom` | User `module.symbol` plus literal kwargs. | Link terms pick bodies from a scene-derived checkbox list and expose **Components** toggles so you only export the axes the policy needs. Joint observation terms reuse the shared **Joint target picker** and — unlike actions — may include both actuated and passive joints, with "All actuated", "All joints", "Passive joints", and "Pick specific joints" exposed directly; "Custom regex" sits behind a small **Advanced** disclosure. One group is authored, and the runtime aliases the missing `critic` group onto `policy` so both heads see the same tensor. Each group is authored independently. Observation rows show the term type as a compact chip next to the editable name; the type is fixed after creation (remove and re-add to change it). ## RL config The **RL config** tab persists the skrl backend, the algorithm (**PPO** or **SAC**), a structured graph-based **Network builder**, the trainer parameters (timesteps, intervals, seed), and the algorithm-config knobs (learning rate, discount factor, ratio clip, batch size, …). Switching algorithm seeds matching defaults. **Experiment paths** (`experiment.name` / `experiment.directory`) default to values derived from the RL task slug and are shown read-only; toggle **Override experiment paths** to write custom values. ### Network builder The network builder is graph-first: it renders the network as a DAG of typed nodes on an inline canvas, with one canvas per role for the active topology. * **`shared`** uses the same architecture for both heads. For PPO this yields a true shared-trunk model (`SharedRLModelCfg`); for SAC it instantiates two independent modules (policy + Q) with the same block spec, because SAC heads can't share weights. * **`separated`** lets you author one graph per role (`policy` / `value` for PPO, `policy` / `q` for SAC). Top-level **presets** are graph templates (for example *PPO – shared MLP*, *SAC – separated MLP*) that materialise the equivalent observation → trunk → head topology directly on the canvas. The palette covers inputs (`observation_input`), dense layers (`mlp`, `residual_mlp`), transforms (`activation`, `layer_norm`), recurrent layers (`rnn`, `gru`, `lstm`), vision (`cnn_backbone` with NatureCNN / IMPALA presets), merge nodes (`concat`, `residual_add`), and a role/algorithm-aware **Heads** section that surfaces `actor_head` + `value_head` for PPO and `actor_head` + `q_head` for SAC. Drag the canvas background to pan, drag a node to reposition it (positions persist in `graphs[role].layout`), and click an edge to delete it. Clicking a node opens an inline inspector below the canvas with the outputs picker (`features_node_id` / `head_node_id`) and the per-node editor. An **Open graph builder** button pops the same graph into a fullscreen dialog for serious authoring. `observation_input` nodes pick a group and a subset of term names from the **Observations** tab. Each term shows read-only tensor metadata — an `image-like` / `flat` badge and a short kind label — so the builder can route image-like terms into a `cnn_backbone` and reject flat terms feeding one. Gaussian log-std controls (`initial_log_std`, `min_log_std`, `max_log_std`) live in the actor head inspector and apply only to the stochastic Gaussian policy. Legacy `{kind, hidden_units, activation}` and `architecture: "mlp"` / `"residual_mlp"` / `"custom"` specs are transparently promoted to a graph on load, so older tasks just render. At runtime, `from runners.skrl.network_builder import build_skrl_model_cfg` maps the persisted spec onto `rlmodule.MlpCfg` / `ResidualMlpCfg` / `SharedRLModelCfg` / `SeparatedRLModelCfg` for the skrl runner. **Verify before saving.** The **Verify** button next to **Save RL config** runs the same validation the save path uses — without persisting — and reports the first problem (for example *"mlp needs exactly 1 input; got 2 — merge multiple branches with a Concat node first"*). The inline canvas also flags structural issues live as red error badges. A passing Verify guarantees Save will succeed. ## Runtime: target, accelerator, and bundle Open the **Runtime** tab to choose how the exported plugin runs: 1. Pick a **`runtime_target`** — `cyberwave-rl-experimental` (plain local Python, no Docker) or `cyberwave-rl` (the dockerized stack). 2. Pick a **`runtime_accelerator`** — `gpu` is the default; `cpu` is the smoke-friendly opt-in. 3. Pin a single **`runtime_bundle`** version (default `latest`). The bundle ships `mjlab` + the chosen runtime + `skrl` together, so callers only ever pin one version. 4. Configure the entrypoints (`scene_cfg_path`, `env_cfg_path` / `env_cfg_factory`, `rl_cfg_path` / `rl_cfg_factory`, optional `registry_path`) inline. 5. Copy the matching **Train locally** snippet for the selected target and accelerator. Both runtimes consume the same exported plugin contract, and the runtime spec (target + accelerator + versions + policy interface) is persisted on the `RLTask` and forwarded to checkpoints and inference dispatch with a `task → checkpoint → launch` merge order. ```bash theme={null} make start make run_cfg arg_overrides="--task=" ``` Real training expects a CUDA GPU. ```bash theme={null} # CPU smoke test python -m train_from_cfg --device=cpu --num_envs=2 --max_steps=10 # Full GPU training (same defaults as cyberwave-rl) python -m train_from_cfg ``` ## Policies and inference The **Policies** tab is the post-training counterpart to the Runtime tab's "Train locally" snippets: upload a trained checkpoint, publish it as a controller, and run inference. Inference deliberately does **not** run MuJoCo — the worker loops Cyberwave joint state through the policy and publishes commands over MQTT. See the dedicated [Uploading policies](/feature-reference/uploading-policies) page for the full checkpoint upload, publish, and inference flow, and [Online controllers](/feature-reference/online-controllers) for serving a published policy. ## Managed training: `training_options.json` A task's async adapter declares which training strategies `cw_request_skill_teaching` (or `POST /api/v1/skill-teaching-requests`) can dispatch by shipping `training_options.json` next to `training.py`. This file is the contract between your adapter and the platform: it names each supported strategy, the JSON-Schema-constrained hyperparameters it accepts, and the defaults applied when a caller doesn't override them. Fetch the resolved options directly instead of guessing the shape: `GET /api/v1/rl-tasks/{uuid}/training-options`, `cw_inspect_rl_tasks(operation="get")`, or the `proposal.training.options` field on a teaching-request proposal all return the current, validated `training_options.json` for a task. ### Shape ```json theme={null} { "schema_version": 1, "strategies": { "": { "parameters": { "...": "a bounded JSON Schema object" }, "defaults": { "...": "values that satisfy 'parameters'" } } } } ``` | Field | Requirement | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `schema_version` | Must be the integer `1`. | | `strategies` | An **object** keyed by strategy key (not a list) — 1 to 16 entries. Each key matches `^[a-z][a-z0-9_.:-]{0,63}$` (for example `rl:ppo`, `imitation:behavior_cloning`). | | `strategies[key].parameters` | A JSON Schema object (`type: "object"`, `additionalProperties: false`, at most 64 properties, nested at most 8 levels). Only `type`, `properties`, `additionalProperties`, `required`, `items`, `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `minItems`, `maxItems`, `minLength`, `maxLength`, `enum`, `title`, `description` are accepted — no `$ref`, `pattern`, or schema-composition keywords, so the descriptor can't fetch remote refs or blow up validation. | | `strategies[key].defaults` | An object satisfying `parameters`; frozen into the job when a caller doesn't override a field. | The whole file is capped at 32 KiB and never executed — it's parsed as data, so authoring it requires no backend source access. ### Worked example This is the real `training_options.json` for the `imitation:behavior_cloning` strategy shipped with the in-tree `cyberwave-rl/examples/kinova_gen3_pick_place` example task: ```json theme={null} { "schema_version": 1, "strategies": { "imitation:behavior_cloning": { "defaults": { "hidden_sizes": [128, 128], "epochs": 300, "batch_size": 256, "learning_rate": 0.0003, "weight_decay": 0.000001, "validation_fraction": 0.1, "seed": 0, "augmentation": {"replicas": 4, "seed": 73} }, "parameters": { "type": "object", "additionalProperties": false, "properties": { "hidden_sizes": {"type": "array", "minItems": 1, "maxItems": 4, "items": {"type": "integer", "minimum": 1, "maximum": 1024}}, "epochs": {"type": "integer", "minimum": 1, "maximum": 10000}, "batch_size": {"type": "integer", "minimum": 1, "maximum": 8192}, "learning_rate": {"type": "number", "exclusiveMinimum": 0, "maximum": 1}, "weight_decay": {"type": "number", "minimum": 0, "maximum": 1}, "validation_fraction": {"type": "number", "exclusiveMinimum": 0, "exclusiveMaximum": 1}, "seed": {"type": "integer", "minimum": 0, "maximum": 4294967295}, "augmentation": { "type": "object", "additionalProperties": false, "required": ["replicas", "seed"], "properties": { "replicas": {"type": "integer", "minimum": 0, "maximum": 32}, "seed": {"type": "integer", "minimum": 0, "maximum": 4294967295} } } } } } } } ``` A caller then requests this strategy with a partial `strategy_config`, for example `{"epochs": 10}`; the backend merges it onto `defaults` (nested objects like `augmentation` are replaced as a whole, not deep-merged) and validates the result against `parameters` before freezing it into the job. ### Validation errors are field-specific Every check names the offending path instead of stopping at the first top-level shape mismatch, so you can iterate directly against the error: * `training_options.json.strategies must be an object keyed by strategy key (e.g. {"rl:ppo": {...}}), got array` — a common first guess is authoring `strategies` as a list of strategy objects instead of a dict keyed by strategy key. * `strategies['rl:ppo'] is missing required field(s): defaults` — a strategy entry must declare exactly `parameters` and `defaults`, nothing else. * `strategies['rl:ppo'].parameters.properties.epochs.type must be one of [...]` — nested schema problems point at the exact property. * `strategies['rl:ppo'].defaults.epochs: 0 is less than the minimum of 1` — invalid defaults report the dotted field path and the underlying JSON Schema message. A `missing_training_input` requirement reported by `cw_request_skill_teaching` or a teaching-request proposal carries this same message, so the specific field is visible without backend source access. ## What's in the exported ZIP? The export is a minimal Python package that drops into `cyberwave-rl/tasks//`: * **`__init__.py`** — generated header that imports your registry (or the default one). * **Your source tree** — exactly as you authored it, with arbitrary nesting and free file structure. * **`scene_cfg.py`** (at the configured `scene_cfg_path`) — the Cyberwave-generated SceneCfg, regenerated from the linked environment. * **`scene_bindings.py`** — semantic role / twin / sensor aliases plus `ACTION_SPEC`, `OBSERVATION_SPEC`, and `RL_CONFIG_SPEC`. * **`actions.py`** (`make_actions()`) and **`observations.py`** (`make_observations()`) — the named wrappers. * **`task_export/`** — the runtime adapters those wrappers import. * **`cyberwave_task_spec.py`** — the strict, canonical Python interchange for scene entities. * **`cyberwave_export.json`** — the export manifest (records runtime target, accelerator, and version pins). * **MuJoCo assets** — one merged `models/mujoco_scene.xml`, one per-entity `models/.xml` carved out of it at build time (so each `EntityCfg.spec_fn` can `MjSpec.from_file` its own slice), and the shared `models/assets/` meshes. * **`registry.py`** — a fallback registry wiring `env_cfg` / `rl_cfg` factories into `register_cyberwave_task`, used only when you don't ship your own `registry_path`. ### Cyberwave-generated vs user-written `scene_bindings.py` is the stable interface between Cyberwave-generated scene metadata and user-written training code. It exposes role aliases (`ROBOT_ENTITY`, `OBJECT_ENTITY`, `SUPPORT_ENTITY`), twin namespace prefixes, namespaced joint-position regex keys, actuator target regexes, camera attach paths, contact sensor names, and a `body_pattern(entity, suffix)` helper. Consume these constants from `env_cfg.py` so renaming a twin or moving a camera in the composer regenerates the bindings without touching MDP code. The editor owns Scene entities, Actions, Observations, RL config, and all generated artefacts. Task-local Python — reward functions, reset / termination logic, metrics, command shaping, and custom observation functions — stays **user-written** under `task_sources/`. Three execution-only modules in `cyberwave-rl` consume the persisted specs so user-written files only have to provide rewards, resets, terminations, commands, and custom observation functions: ```python theme={null} from task_export.action_specs import make_action_cfgs # ACTION_SPEC → {name: ActionTermCfg} from task_export.observation_specs import make_observation_groups # OBSERVATION_SPEC → {group: ObservationGroupCfg} from task_export.rl_config_specs import make_rl_cfg_from_spec # RL_CONFIG_SPEC → ReinforcementLearningCfg ``` ZIP **import** is intentionally document-only for the generated paths: `scene_cfg.py`, `scene_bindings.py`, and `cyberwave_task_spec.py` are skipped on import and the response carries an explicit warning. Scene entities are **not** auto-restored from a bundled `cyberwave_task_spec.py` — re-compose them in the editor. The export ZIP always carries fresh bytes for the Cyberwave-generated files, so re-running the composer (or hitting `regenerate-scene-cfg`) is enough to refresh the artefact. ## API surface All endpoints are under `/api/v1/rl-tasks` and require authentication. | Method & path | Purpose | | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `GET/POST /api/v1/rl-tasks` | List / create RL tasks. | | `GET/PUT/DELETE /api/v1/rl-tasks/{uuid}` | Read, update, soft-delete (independent of the linked environment). | | `POST /api/v1/rl-tasks/{uuid}/clone` | Duplicate the task definition (metadata, runtime contract, source files, scene entities) into a new row; checkpoints and inference runs are not cloned. | | `GET /api/v1/rl-tasks/{uuid}/source-files` | List and read/write/delete the user-written source tree (content endpoints live under the same prefix). Unsafe paths and uncompilable Python are rejected. | | `POST /api/v1/rl-tasks/{uuid}/regenerate-scene-cfg` | Rewrite the SceneCfg at the configured path plus every spec-derived file (task spec, `scene_bindings.py`, `actions.py`, `observations.py`, `task_export/`). This is the Files-tab "Regenerate all". | | `POST /api/v1/rl-tasks/{uuid}/regenerate-task-spec` | Regenerate only the spec-derived files (no SceneCfg rebuild); used by the Actions/Observations "Save & regenerate". | | `POST /api/v1/rl-tasks/{uuid}/generate-env-cfg` | Write a runnable starter `env_cfg.py` (user-written). Returns **409** if one already exists unless `overwrite=true`. | | `GET /api/v1/rl-tasks/{uuid}/export.zip` | Download the runnable plugin ZIP. | | `POST /api/v1/rl-tasks/import.zip` | Import a ZIP as a new task. | | `POST /api/v1/rl-tasks/{uuid}/import.zip` | Refresh an existing task from a ZIP (generated files skipped; a bundled task spec surfaces a warning). | | `GET/PUT /api/v1/rl-tasks/{uuid}/actions` | Read / write the action spec. | | `GET/PUT /api/v1/rl-tasks/{uuid}/observations` | Read / write the observation spec. | | `GET/PUT /api/v1/rl-tasks/{uuid}/rl-config` | Read / write the RL config spec. | | `GET /api/v1/rl-tasks/{uuid}/orchestration-hints` | Scene-derived dropdown data: articulation entities, actuator groups and types per entity, declared joint/body names, actuated vs passive joint lists, and configured camera / contact sensors. | | `GET /api/v1/rl-tasks/{uuid}/training-options` | Read the task's validated `training_options.json` (see [Managed training](#managed-training-training-options-json)). | | `GET/POST/PUT /api/v1/rl-tasks/{uuid}/scene-entities` | List, create, and update scene entities. | | `PATCH/DELETE /api/v1/rl-tasks/{uuid}/scene-entities/{entity_uuid}` | Partially update or delete a single scene entity. | The `RLTask` response surfaces the action, observation, and RL-config specs as `action_spec`, `observation_spec`, and `rl_config_spec` JSON fields. It also surfaces the two **command specs** split by lifecycle — `training_command_spec` and `inference_command_spec` — each paired with an explicit lifecycle switch (`training_command_setup_enabled` / `inference_command_setup_enabled`). Unlike the actions/observations/rl-config specs (which have dedicated `GET/PUT` endpoints), the command specs and their switches are read from the `RLTask` response and written through `POST`/`PUT /api/v1/rl-tasks/{uuid}` (mirrored by the SDK's `set_training_command_spec` / `set_inference_command_spec`). The spec GET, the regenerate endpoints, and the export ZIP all produce byte-identical output for the same scene-entity rows, so re-reading and re-exporting are always consistent. If a body can't be resolved while splitting the MuJoCo scene, the request fails with **HTTP 400** naming the failing entity and the selectors that were tried — check the twin selectors and re-export. ## Inference Commands RL tasks can declare **inference commands** that define a live control surface for deployed policies. Each command declares: * A **payload schema** (typed fields like `target_position: vec3`, `object_position: vec3`) * A **source binding** (transport + topic, e.g. MQTT) When you deploy an RL task controller, the Online Controllers panel shows schema-driven inputs matching your inference command spec. Submitting values sends them to the running controller over MQTT, updating the policy's command observations in real time. Common use cases: * **Position controllers**: Set a target EE pose for reach tasks * **Waypoint controllers**: Set the detected object center for inspection trajectory generation Commands are authored as first-class **terms**, like observation terms: each term references a `CommandTermCfg` subclass (`module.symbol`) implemented in the task's `env_cfg.py`. Add and edit terms in the editor's **Commands tab** (term name, `module.symbol`, lifecycle fields, kwargs) or from the SDK (`set_training_command_spec` / `set_inference_command_spec`); the term's Python implementation lives in the task's source files. The Commands tab has two explicit lifecycle switches — **Training command setup** and **Inference command setup**. Turning one off clears its spec by design (a disabled lifecycle is "deliberately off", not a forgotten upload); turning it on requires at least one code-backed term. From the SDK, pass `enabled=` to `set_training_command_spec` / `set_inference_command_spec` to set a switch explicitly, or omit it and the switch is derived from whether the spec has commands. ## Where to go next Build the OpenArm pick-up task end-to-end in Python, from empty workspace to deployed policy. Upload trained checkpoints, publish them as controllers, and run inference. Serve a published policy as a live controller. Configure cameras and contact sensors on scene entities. Build the MuJoCo environment that backs your RL task's SceneCfg. # Authentication Source: https://docs.cyberwave.com/feature-reference/setup-cyberwave Set up API credentials to connect to Cyberwave ## Overview Cyberwave uses API tokens to authenticate requests. You'll need a token to: * Connect the Python SDK * Make REST API calls * Establish MQTT connections Each token is scoped to a specific workspace, giving you isolated access per workspace. *** ## Creating an API Token Go to [cyberwave.com](https://cyberwave.com) and sign in to your account. Click your profile icon and select **Profile** or go directly to [cyberwave.com/profile](https://cyberwave.com/profile). Open **Access** (**Profile → Access**) and click **Create Token**. Select the workspace you want the token scoped to, then copy the token immediately — it won't be shown again. Keep your API token secure. Don't commit it to version control or share it publicly. *** ## Using Your API Token ### Environment Variable (Recommended) Set your API token as an environment variable: ```bash theme={null} export CYBERWAVE_API_KEY="cw_your_token_here" ``` The SDK automatically reads this variable: ```python theme={null} import cyberwave as cw # Automatically uses CYBERWAVE_API_KEY robot = cw.twin("the-robot-studio/so101") ``` ### Direct Configuration Pass the API token directly when initializing the client: ```python theme={null} from cyberwave import Cyberwave client = Cyberwave(api_key="cw_your_token_here") ``` *** ## Environment Variables The SDK supports these environment variables: | Variable | Description | | -------------------------- | --------------------------------------------------- | | `CYBERWAVE_API_KEY` | Your API token for authentication | | `CYBERWAVE_BASE_URL` | API base URL (default: `https://api.cyberwave.com`) | | `CYBERWAVE_ENVIRONMENT_ID` | Default environment UUID | | `CYBERWAVE_WORKSPACE_ID` | Default workspace UUID | | `CYBERWAVE_MQTT_HOST` | MQTT broker host (default: `mqtt.cyberwave.com`) | | `CYBERWAVE_MQTT_PORT` | MQTT broker port (default: `8883`) | ### Example `.env` File ```bash theme={null} CYBERWAVE_API_KEY=cw_a1b2c3d4e5f6... CYBERWAVE_ENVIRONMENT_ID=1e48b1a5-ff2b-45ba-a854-a2c2df561852 ``` Load with [python-dotenv](https://pypi.org/project/python-dotenv/): ```python theme={null} from dotenv import load_dotenv load_dotenv() import cyberwave as cw robot = cw.twin("the-robot-studio/so101") ``` *** ## MQTT Authentication For real-time features (video streaming, teleoperation, live joint updates), the SDK connects to MQTT automatically using your API token. The MQTT connection is lazily initialized — it connects on the first call that requires it (e.g., subscribing to joint updates). ```python theme={null} from cyberwave import Cyberwave client = Cyberwave(api_key="cw_your_token_here") robot = client.twin("the-robot-studio/so101") # MQTT connects automatically on the first subscription robot.subscribe_joints(lambda data: print(f"Joints: {data}")) ``` The default MQTT connection uses TLS on port 8883. ### Custom MQTT Settings Override MQTT connection settings if needed: ```python theme={null} client = Cyberwave( api_key="cw_your_token_here", mqtt_host="mqtt.cyberwave.com", mqtt_port=8883 ) ``` *** ## REST API Authentication For direct REST API calls, include your API token in the `Authorization` header: ```bash theme={null} curl -X GET "https://api.cyberwave.com/api/v1/assets/" \ -H "Authorization: Bearer cw_your_token_here" ``` Both `Bearer` and `Token` prefixes are accepted. *** ## Troubleshooting * Verify your API token is correct and hasn't been revoked. * Check that the environment variable is set: `echo $CYBERWAVE_API_KEY`. * Create a new token under **Profile → Access** if needed. See [API tokens](/feature-reference/api-tokens). The SDK couldn't find credentials. Either: * Set the `CYBERWAVE_API_KEY` environment variable. * Pass `api_key` directly to `Cyberwave()`. * Check that your network allows outbound connections on port **8883** (TLS). * Verify your API token is valid and not revoked. * The MQTT client connects lazily. Call a subscription method to trigger the connection. *** ## Connectivity Requirements for Running an Edge If you're running the Cyberwave Edge runtime (Edge Core plus drivers) on your own hardware, here's every connection it needs. All of these are **outbound-initiated from the edge** — you generally don't need to open any inbound ports on your network. | Purpose | Protocol / Port | Destination | Required when | | -------------------------------------------- | -------------------------------- | ------------------------------- | ---------------------------------------------------------------- | | REST API | TCP `443` (HTTPS) | `api.cyberwave.com` | Always | | MQTT (telemetry, commands, WebRTC signaling) | TCP `8883` (MQTT over TLS) | `mqtt.cyberwave.com` | Always | | TURN relay over TLS (default) | TCP `443` | `tls.turn.cyberwave.com` | Streaming video | | STUN | UDP `3478` | `turn.cyberwave.com` | Streaming video (optional; the TLS relay connects without it) | | Zenoh peer discovery | UDP multicast, local subnet only | Local network | Running more than one driver/worker process on the edge | | Zenoh router (multi-host) | TCP `7447` | Between edge hosts on your site | Only if drivers are split across multiple hosts on the same site | For the full picture of why each protocol is used, see [Architecture → Video Streaming (WebRTC)](/feature-reference/architecture/architecture#video-streaming-webrtc) and [Architecture → Local Data Bus (Zenoh)](/feature-reference/architecture/architecture#local-data-bus-zenoh). *** ## Next Steps Create your first digital twin Full SDK documentation # Telemetry event time Source: https://docs.cyberwave.com/feature-reference/telemetry-event-time What the timestamp field means on a telemetry row, and how it differs from the timestamp on the wire Telemetry, driver-log and metrics responses carry **`timestamp`**: when the sample was *acquired*, in wall clock, never later than the moment Cyberwave received it. It is the field to order, window and plot on. ```json theme={null} { "uuid": "…", "timestamp": "2026-07-31T12:00:00+00:00", "event_type": "twin_position_update", "metadata": { "x": 1.0 } } ``` Endpoints that return it: | Endpoint | Field | | --------------------------------------------- | ------------------- | | `GET /api/v1/twins/{uuid}/telemetry` | `items[].timestamp` | | `GET /api/v1/twins/{uuid}/logs` | `items[].timestamp` | | `GET /api/v1/environments/{uuid}/driver-logs` | `items[].timestamp` | | `GET /api/v1/twins/{uuid}/connection-events` | `timestamp` | | `GET /api/v1/twins/{uuid}/metrics` | `timestamp` | | `GET /api/v1/twins/{uuid}/latest-track` | `timestamp` | ## Not the same as the `timestamp` on MQTT A message you read straight off the broker carries its own `timestamp` — the publishing host's wall clock at the moment it published, which includes read, serialization and queueing delay. For a camera it also includes exposure and transfer. Publish time and acquisition time differ by that latency, so a live view fed from MQTT and a replay fed from the API can disagree by it for the same sample. If you need acquisition time on a live subscription, read the source-time fields on the payload rather than the wire `timestamp` — once your publisher sends them. No publisher emits them yet; until yours does, the API is the only place acquisition time is available. The field name is unchanged, and so is the value for publishers that send no source-time envelope: the publisher's own stamp, bounded by receipt. Publishers that do send one get their acquisition stamp carried across clock domains instead, which is closer to the truth by whatever their publish latency was. # Twin joint home positions Source: https://docs.cyberwave.com/feature-reference/twin-joint-home-positions Editing twin joint defaults from manual control and how they flow into RL tasks ## Source of truth Each twin keeps a snapshot of its asset's universal schema. The default pose of every controllable joint lives in `twin.universal_schema.joints[].home_position`. The "Manual Control" sliders, the 3D viewer, and the RL task scene entity composer all read from that same field, so editing a slider in edit mode and reading the value back in an RL task always agrees. ## What edit mode persists Edit-mode writes are the **only** path that updates the durable home pose. They opt in by sending `as_home_position: true` on `PUT /api/v1/twins/{uuid}/joint_states` (or the per-joint endpoint). With the flag set, Cyberwave updates: * `Twin.joint_states[joint_name].position` — runtime state. * `Twin.universal_schema.joints[i].home_position` — durable default. The frontend posts the *entire* controllable pose (every joint position, including explicit `0.0`s) when the operator saves an edit-mode pose. Every controllable joint gets an explicit `home_position` after the save — no joint is left as `null` — so the RL task composer never labels a joint as `default (0.0)` while manual control shows the same `0.0`. Velocity and effort updates still only touch `Twin.joint_states`. ## What live/teleop writes do *not* persist `PUT /api/v1/twins/{uuid}/joint_states` without `as_home_position` (the default) only writes `Twin.joint_states`. SDK callers, edge drivers streaming joint positions, MQTT-driven teleop, and the legacy joint-state syncs from physical hardware therefore never overwrite the schema home. The durable home stays whatever the operator last saved from edit mode. ## Frontend reads twin schema first The 3D viewer and the manual control sliders read `twin.universal_schema.joints[].home_position` from the `GET /api/v1/twins/{uuid}` response *before* falling back to the asset-level `Asset.universal_schema`. That guarantees per-twin edit-mode homes win over workspace-shared defaults, and that two twins of the same asset can carry different durable poses. ## Reads fall back to the schema home `GET /api/v1/twins/{uuid}/joint_states` returns `home_position` for any controllable joint without an explicit runtime entry. The same fallback is used by `Twin._derive_joint_states()` so MJCF composition, RL task hints, and the manual control bar all agree on the same default pose. # Live position & camera frames Source: https://docs.cyberwave.com/feature-reference/twin-live-position-and-frames Read where a GPS-positioned robot is right now, and pull its latest camera frame on demand. Two endpoints for reading a robot's current state over plain HTTPS, without subscribing to MQTT or opening a video stream. Both are polling endpoints: you ask, you get the latest value. ## Where is it now? ``` GET /api/v1/twins/{twin_uuid}/live-position ``` Returns the robot's current GNSS position, in both WGS-84 and your environment's local frame: ```json theme={null} { "twin_uuid": "…", "source": "gps", "latitude": 48.1490, "longitude": 17.1080, "altitudeM": 164.4, "altitudeReference": "fix", "position": { "x": 3.0, "y": 4.0, "z": 12.0 }, "yawDeg": 90.0, "takeoffAltitudeOffsetM": 10.75, "ageSeconds": 0.4, "state": "flying", "fix": { "fix_type": "3d", "satellite_count": 14 }, "battery": { "percent": 78.0 } } ``` Requires the twin to be [GPS-positioned](/feature-reference/environment-editor/geo-reference). A GNSS fix typically arrives at 1–2 Hz, so polling faster returns the same fix with a larger `ageSeconds`. **A `404` means the position is genuinely unknown** — no recent fix has arrived. It deliberately does *not* fall back to the position the twin was placed at in the editor: that placement is not georeferenced, so returning it would be a confident wrong answer about where a real robot is. `takeoffAltitudeOffsetM` is the height above the point the aircraft took off from, present only once a take-off has been observed. `battery` and `state` are omitted when the robot has not reported them, rather than being reported as zero. `GET /api/v1/twins/{uuid}/telemetry` is a different thing: it queries *historical* recorded telemetry and requires a time range. Use `live-position` for the current value. ## Give me a picture, now ``` GET /api/v1/twins/{twin_uuid}/latest-frame?pull=true ``` Returns `image/jpeg`. Without `pull`, this endpoint serves whatever frame is already cached and `404`s if there is none. With `pull=true`, it asks the robot to take a photo and waits briefly for the answer, so you get a frame even when nothing is streaming. | Query param | Meaning | | ----------- | ------------------------------------------------------------- | | `pull=true` | Ask the device for a fresh photo if nothing recent is cached. | | `sensor_id` | Which camera, on a robot with more than one. | | `mock=true` | Return a fixed test image — handy for wiring up a client. | The `X-Frame-Pulled` response header tells you whether the frame was freshly captured (`true`) or served from cache (`false`). **Frame rate is set by how often you ask**, capped at roughly 5 frames per second — a faster poll returns the cached frame rather than putting another capture request on the robot. Requires a driver that supports on-demand photo capture; a `504` means no frame could be produced — the robot was asked and did not answer, its driver does not support on-demand capture, or it has no camera. When you pass `sensor_id`, you only ever get a frame from that camera. If a photo arrives from a different one — possible on a multi-camera robot when two requests overlap — it is cached under its own camera and this request answers `504` rather than handing you the wrong picture. # Saved poses Source: https://docs.cyberwave.com/feature-reference/twin-saved-poses Save and re-apply named joint poses for a twin from Edit, Live, and Simulate mode ## What it is Poses are named joint-angle snapshots you can save and re-apply later, from the Poses section of a twin's right-hand panel (below Manual Control / Joint Editing). ## Where it works * **Edit mode**: save/edit/delete/apply poses against the twin's rest state. * **Live mode**: save captures the twin's current live telemetry (not the rest state); applying a pose sends it to the real device over MQTT. * **Simulate mode**: save captures the current simulated joint state; applying a pose drives the simulator over MQTT. ## Scopes A pose can be saved at twin, environment, or asset scope, controlling whether it's specific to this twin, this environment, or shared across every instance of the asset. # Uploading policies Source: https://docs.cyberwave.com/feature-reference/uploading-policies Upload a locally trained checkpoint to its RL task, then publish it as an online controller or run cloud inference against your environment. ## What is a trained policy? A **trained policy** is a **checkpoint** — the model weights produced by training an [RL task](/feature-reference/rl-tasks) locally with `cyberwave-rl` or `cyberwave-rl-experimental` (for example a `best_agent.pt`). The checkpoint belongs to the RL task it was trained against: you author and export the task, train it on your own machine or GPU, then upload the resulting checkpoint **back to the same RL task** so the platform can serve it. Once a checkpoint lives on its RL task you can: * **Publish it as an online controller** and assign it to a twin. * **Run cloud inference** that loops live joint state through the policy. * **Pull it back into MuJoCo locally** to replay it with the Python SDK. Everything below happens in the **Policies** tab of the RL task editor (or through the matching REST / Python SDK calls). ## Supported checkpoint contract Read this section **before training or uploading**. File storage accepts weights; successful upload does not establish that the hosted controller can execute them. The current legacy hosted path loads **skrl agent checkpoints** produced for an exported Cyberwave RL task using `cyberwave-rl` or `cyberwave-rl-experimental`. Register genuine skrl checkpoints with `metadata={"checkpoint_format": "skrl"}` through the MCP checkpoint registration operation. File extensions such as `.pt` do not identify the runtime format. Arbitrary PyTorch modules, TorchScript actors, and Stable-Baselines3 checkpoints are **not currently supported** by this path; renaming files or declaring them as skrl does not convert them. Follow [RL Tasks](/feature-reference/rl-tasks) for the exported task/source contract and [Train an RL Policy](/tutorials/train-rl-policy) for the training workflow. Keep the checkpoint paired with its task's observation ordering and history, preprocessing, action ordering/scaling and units, control timing, runtime versions and dependencies. Custom observation/action logic belongs in the task's supported source/configuration interfaces, not just in a weights file or dimension metadata. Manifest-based policies retain their separate provenance/evaluation requirements. With MCP, call `cw_deploy_rl_policy(operation="inspect", rl_task_uuid=...)` before training for documentation links and again after registration for compatibility blockers. Checks at publication, assignment and start are static checks, not proof of successful execution. Validate the complete policy in simulation before live use. ### Resetting a hosted simulation Use `cw_stop_simulation`, then `cw_start_simulation` to reset. Each start creates a fresh simulation workload and worker with new MuJoCo model/data loaded from the current scene configuration. Stop also stops the environment's controllers. Wait for the new simulation to be running before starting the assigned controller, or explicitly request `auto_run_controllers` when starting the simulation. There is no separate in-place episode-reset API. Keep scene configuration, initial conditions and any randomization consistent when comparing trials. ## The happy path Export your RL task, then train it with `cyberwave-rl` / `cyberwave-rl-experimental` on your own machine. Training produces a checkpoint file such as `best_agent.pt`. Upload the checkpoint file back to its RL task — via the dashboard, the Python SDK, or REST. Runtime and policy-interface fields are inherited from the parent RL task. Choose one (or more): * **Publish as a controller** — turn the checkpoint into an assignable online controller. * **Run inference** — dispatch a cloud workload that drives a twin through the policy over MQTT. * **Use in MuJoCo locally** — download the checkpoint with the SDK and replay it locally. ## Upload a checkpoint Uploading stores the weights and registers the checkpoint against the RL task in a single call. The new checkpoint inherits the parent task's runtime target, accelerator, version pins, and policy interface. File uploads accept **`.pt`, `.pth`, or `.zip`** only, up to a **maximum size of 512 MB**. For weights that exceed this limit, [register an external URL](#register-an-external-url) instead. 1. Open the RL task and go to the **Policies** tab. 2. Choose **Upload checkpoint** and select your `.pt` / `.pth` / `.zip` file. 3. Optionally give it a **name** and **description**. Uploaded checkpoints appear in the list with an **Uploaded** badge (URL-registered ones show a **URL** badge). Each row exposes **Download** and **Delete**. ```python theme={null} from cyberwave import Cyberwave from cyberwave.rl_tasks import RLTaskClient cw = Cyberwave() # reads CYBERWAVE_BASE_URL + CYBERWAVE_API_KEY rl = RLTaskClient(cw) checkpoint = rl.upload_checkpoint( "", "logs/openarm-pickup/run-1/checkpoints/best_agent.pt", name="best_agent", description="OpenArm pick-up, 1M steps", ) print(checkpoint["uuid"]) ``` ```bash theme={null} curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/rl-tasks//checkpoints/upload" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -F "file=@logs/openarm-pickup/run-1/checkpoints/best_agent.pt" \ -F "name=best_agent" \ -F "description=OpenArm pick-up, 1M steps" ``` ### Register an external URL If your weights are already hosted elsewhere, register them by URL instead of uploading bytes. This path also lets you override the inherited runtime target, accelerator, version pins, and policy interface. ```python theme={null} from cyberwave import Cyberwave from cyberwave.rl_tasks import RLTaskClient cw = Cyberwave() rl = RLTaskClient(cw) checkpoint = rl.register_checkpoint( "", name="best_agent (remote)", weights_url="https://example.com/weights/best_agent.pt", ) ``` ```bash theme={null} curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/rl-tasks//checkpoints" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "weights_url": "https://example.com/weights/best_agent.pt", "name": "best_agent (remote)" }' ``` List, inspect, and remove checkpoints with `GET .../checkpoints`, `GET .../checkpoints/{checkpoint-uuid}`, and `DELETE .../checkpoints/{checkpoint-uuid}`. See the [endpoint reference](#endpoint-reference). ## Publish as a controller Publishing a checkpoint creates a **ControllerPolicy** — an `rltask` [online controller](/feature-reference/online-controllers) that you can assign to a twin. The controller runs the policy in its own controller-host cloud node and drives the plant over MQTT, so the same policy can target a simulated or a live robot. From the **Policies** tab, select a checkpoint and choose **Publish as controller**. Optionally set a **controller name** and **description**. ```bash theme={null} curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/rl-tasks//checkpoints//publish-controller" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "controller_name": "my-policy-online", "controller_description": "Published from best_agent checkpoint" }' ``` The response includes the new controller policy's `controller_policy_uuid` and `controller_policy_slug`. From there it behaves like any other online controller — see [Online controllers](/feature-reference/online-controllers) for assigning and running it. ## Run inference Inference dispatches a **cloud workload** that loads the checkpoint, loops Cyberwave joint state through the policy, and publishes commands over MQTT. This inference path **does not run MuJoCo**. It is a **state-through-policy loop** — live joint state in, policy commands out — not a physics rollout. If you want a full physics simulation, use a [simulated plant with an online controller](/feature-reference/online-controllers) instead. ```python theme={null} from cyberwave import Cyberwave from cyberwave.rl_tasks import RLTaskClient cw = Cyberwave() rl = RLTaskClient(cw) run = rl.launch_inference( "", checkpoint_uuid="", twin_uuid="", # the robot twin to drive max_steps=1000, control_rate_hz=50, ) print(run["uuid"]) # Later: list past runs (each row links to its cloud workload). for r in rl.list_inference_runs(""): print(r["uuid"], r.get("workload_uuid")) ``` ```bash theme={null} curl -X POST \ "$CYBERWAVE_BASE_URL/api/v1/rl-tasks//inference" \ -H "Authorization: Bearer $CYBERWAVE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "checkpoint_uuid": "", "twin_uuid": "", "max_steps": 1000, "control_rate_hz": 50 }' ``` * **`checkpoint_uuid`** (preferred) selects which policy to run. * **`twin_uuid`** is the robot twin the policy drives. * **`mode`**, **`max_steps`**, and **`control_rate_hz`** are optional and tune the loop. List past inference runs with `GET /api/v1/rl-tasks/{uuid}/inference`. ## Use in MuJoCo locally To replay a checkpoint in MuJoCo on your own machine, select it in the **Policies** tab — the dashboard reveals a copy-paste snippet that uses the Python SDK to download the checkpoint, stage it into the layout `cyberwave-rl`'s play step expects, and play it locally. ```python theme={null} from cyberwave import Cyberwave from cyberwave.rl_tasks import RLTaskClient cw = Cyberwave() rl = RLTaskClient(cw) # 1. Download the registered checkpoint's weights. local = rl.download_checkpoint( "", "", destination="/tmp/best_agent.pt", ) # 2. Stage it into the layout cyberwave-rl's play step expects: # logs//uploaded/checkpoints/best_agent.pt staged = RLTaskClient.prepare_checkpoint_for_play( task_id="OpenArm-pick-up-demo", checkpoint_path=local, ) print(f"Staged checkpoint at: {staged}") # 3. Run cyberwave-rl's play entrypoint against the staged run. ``` The Python SDK exposes `upload_checkpoint(...)`, `download_checkpoint(...)`, and the static `prepare_checkpoint_for_play(...)` helper on `RLTaskClient`, so the full round trip — train, upload, replay — stays in one place. ## Endpoint reference | Method | Path | Purpose | | -------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | `POST` | `/api/v1/rl-tasks/{uuid}/checkpoints/upload` | Upload a checkpoint file (`.pt` / `.pth` / `.zip`, max 512 MB) and register it. | | `POST` | `/api/v1/rl-tasks/{uuid}/checkpoints` | Register a checkpoint by external `weights_url`. | | `GET` | `/api/v1/rl-tasks/{uuid}/checkpoints` | List checkpoints for an RL task. | | `GET` | `/api/v1/rl-tasks/{uuid}/checkpoints/{checkpoint_uuid}` | Get a single checkpoint. | | `DELETE` | `/api/v1/rl-tasks/{uuid}/checkpoints/{checkpoint_uuid}` | Delete a checkpoint. | | `POST` | `/api/v1/rl-tasks/{uuid}/checkpoints/{checkpoint_uuid}/publish-controller` | Publish a checkpoint as an `rltask` online controller. | | `POST` | `/api/v1/rl-tasks/{uuid}/inference` | Dispatch a cloud inference run (state-through-policy, no MuJoCo). | | `GET` | `/api/v1/rl-tasks/{uuid}/inference` | List inference runs. | ## Where to go next Author, export, and train the RL task a checkpoint belongs to. Run a published policy in its own controller host against a simulated or live robot. Explore other model types and training flows on the platform. # Build and run workflows Source: https://docs.cyberwave.com/feature-reference/workflows Automate robot operations with visual workflow orchestration ## What are Workflows? Failed simulation runs show their runtime alerts in **Simulate**. Open the execution details to inspect the failure. Workflows in Cyberwave let you create automated sequences of robot operations. Connect nodes visually to build complex behaviors without writing procedural code. Workflows can run **on the cloud** (Celery tasks) or **on the edge device** depending on the trigger type. Cloud triggers handle schedule, webhook, event, and manual execution. The `camera_frame` trigger runs ML inference directly on the edge — no video leaves the device. *** ## Workflow Components ### Nodes Nodes are the building blocks of workflows. Each node performs a specific action. Nodes are organised into a hybrid robotics + automation taxonomy. The same categories show up in the editor palette and on `GET /api/v1/workflows/config` (`node_categories`), so the docs, the API, and the UI all read from the same `WorkflowNodeCategory` enum (see `cyberwave-backend/src/lib/node_categories.py`). Categories with no nodes today (Perception) are reserved — they appear in the API response but are hidden in the palette until they ship. Start the workflow on an event, schedule, or incoming message: manual, schedule, webhook, event, MQTT, email, camera\_frame, alert Pull snapshots and samples from sensors, cameras, and external systems on demand: `data_source` Convert raw signals into reliable observations — reserved for object trackers, sensor fusion, IMU filtering, ASR (no nodes ship today) Reshape, convert, route, multiplex, or fan out data: `json_parser`, `annotate`, `anonymize`, `send_depth` (edge-only) Store and retrieve memory over time: `create_asset`, `edit_asset`, `create_attachment`, `update_attachment`, `video_tagger` Use models for interpretation, reasoning, or prediction: `call_model` (cloud VLM/LLM and edge ML) Choose what happens next: `conditional`, `loop`; FSM / Behavior Tree / Rule Engine on the roadmap Execute physical or twin-side actions: `twin_control` (Move Twin); future joint / gripper / navigation primitives Talk to external systems and run user-supplied logic: `http_request`, `send_email`, `send_mqtt`, `code` (edge-only) Guard, validate, observe, and alert: `send_alert`; validators, watchdogs, e-stop guards, and anomaly detectors are on the roadmap ### Connections Connections define the execution flow between nodes: * **Sequential**: Execute nodes one after another * **Parallel**: Execute multiple nodes simultaneously * **Conditional**: Branch based on conditions Connection validation prevents invalid graphs: trigger nodes cannot accept incoming connections, cycles are blocked, and `camera_frame` triggers can only connect to `call_model` nodes. *** ## Trigger Types | Trigger | Where it runs | How it fires | | ---------------- | --------------------- | ------------------------------------------------------------ | | **Manual** | Cloud (Celery) | User clicks "Run" in the UI or triggers via SDK/API | | **Schedule** | Cloud (Celery) | Cron or interval timer | | **Webhook** | Cloud (Celery) | HTTP POST to a webhook URL | | **Event** | Cloud (Celery) | Business event matching conditions | | **MQTT** | Cloud (Celery) | MQTT message on a topic | | **Zenoh** | Edge/local data plane | Zenoh message on a key expression | | **Email** | Cloud (Celery) | Incoming email | | **Camera Frame** | **Edge device** | Every camera frame, locally — never sends video to the cloud | *** ## Creating a Workflow Navigate to **Workflows** in the dashboard. Click **Create Workflow**. Give it a name, optional slug (unique within the workspace), and visibility. Drag nodes from the palette to the canvas. Connect nodes by dragging from output to input ports. Configure each node's parameters (twin UUID, model, confidence threshold, send-alert metadata, etc.). Click **Activate**. Edge workflows (`run_on_edge: true`) automatically publish a `sync_workflows` MQTT command to each referenced twin's Edge Core, which immediately pulls and reloads the freshly compiled worker — no CLI step needed. The editor locks the graph while active, so the natural edit flow (Deactivate → edit → Activate) republishes through the same signal. ```bash theme={null} # List workflows cyberwave workflow list cyberwave workflow list --json # Create from template cyberwave workflow create --template motion-detection # Create with custom name cyberwave workflow create -n "My Workflow" # Show workflow details (interactive selection if UUID omitted) cyberwave workflow show cyberwave workflow show # Activate / deactivate cyberwave workflow activate cyberwave workflow deactivate # Sync workflow to edge node(s) cyberwave workflow sync cyberwave workflow sync --edge-active # filter selector to active edge workflows cyberwave workflow sync --base-url http://192.168.10.101:8000 # Inspect what the edge compiler emitted (and why) for a workflow cyberwave workflow compile cyberwave workflow compile --json # raw API response # Download the generated worker source cyberwave workflow compile-source # to stdout cyberwave workflow compile-source -o ./wf.py # to a file # Delete cyberwave workflow delete --yes ``` All subcommands accept `--base-url` / `-u` to override the API URL. When a UUID argument is omitted, an interactive arrow-key selector is shown. `compile` wraps `/api/v1/workflows/{uuid}/compile` and reports the artifact shape the unified edge compiler emitted (`perception` for camera-frame graphs, `navigation` for graphs with a Move Twin node), the auto-derived target twin, model requirements, and any compiler warnings — including the diagnostic from the backend's `diagnose_compilation_dispatch` helper when the workflow's graph shape isn't compilable. Reach for it when `cyberwave workflow sync` reports the cloud isn't shipping a workflow to your edge. `compile-source` is the companion download for the generated `wf_*.py`. ```python theme={null} from cyberwave import Cyberwave cw = Cyberwave(api_key="your_api_key") workflows = cw.workflows.list() run = cw.workflows.trigger("workflow-uuid", inputs={"speed": 0.5}) run.wait(timeout=60) print(f"Workflow finished: {run.status}") ``` *** ## Edge Workflows (Camera Frame) The `camera_frame` trigger is designed for on-device ML inference. The backend generates a Python worker file that runs directly on the edge — raw video frames never leave the device. Choose a **Source Twin** with a declared camera, then select **Source Sensor**. A twin with one camera fills the sensor automatically. Older saved camera values remain visible until you choose a declared camera. Source selection does not activate the workflow. ### How it works ```mermaid theme={null} sequenceDiagram participant UI as Workflow Editor participant BE as Backend participant Edge as Edge Device UI->>BE: Activate workflow (camera_frame → call_model → send_alert) Edge->>BE: GET /api/v1/workflows/edge-sync/{twin_uuid} BE->>Edge: Worker source + model requirements Edge->>Edge: Write wf_.py, install models Edge->>Edge: Runtime loads worker, registers @cw.on_frame loop Every frame Edge->>Edge: model.predict(frame) Edge->>BE: cw.publish_alert(...) when send_alert fires end ``` For open-vocabulary edge models (YOLOE-26 text/visual, YOLO-World), set the **Prompt** field on the `call_model` node to drive `set_classes` at inference time. The camera worker forwards the static prompt into `model.predict(..., prompt=...)`. See [Prompting Call Model](./workflows/call-model-prompt) for the full guide, including the comma-list vs. single-phrase semantics and the camera-only limitation that reference-wired prompts are not supported. ### Migrating from `emit_event` Older workflows configured implicit alerts via an `emit_event` block on the `call_model` node (`event_type`, `severity`, `emit_mode`, `cooldown_seconds`). That path was removed: `emit_event` is no longer a schema field, the next save of any `call_model` node strips leftover `emit_event` values from `parameters` and `metadata.input_mappings` so the saved graph converges to the post-migration shape, and `call_model` no longer publishes alerts on its own. Pre-migration rows that haven't been re-saved yet still load — codegen also drops `emit_event` during compilation, so they ship a worker that runs inference but publishes nothing. To raise alerts from detections, wire an explicit `send_alert` node downstream of `call_model`. The legacy fields map onto existing nodes: | Legacy `emit_event` field | Replacement | | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled: false` | Don't add a `send_alert` node | | `event_type` / `severity` | `send_alert.parameters.alert_type` / `severity` | | `emit_mode: on_enter` / `on_change` | Insert a `detection_event_gate` between `call_model` and `send_alert` | | `cooldown_seconds` | Insert a `timed_condition` (`mode: debounce`, `cooldown_s: `) before `send_alert` | | Implicit `force=True` (no UI knob — the legacy path always passed it) | The emitter defaults `force=True` on a `send_alert` whose direct upstream is `call_model`, so the per-frame loop bypasses the backend's content-hash dedupe and identical consecutive detections still raise distinct alerts. Set `send_alert.parameters.force` to `false` to opt back into the dedupe. When a gate or `timed_condition` sits between `call_model` and `send_alert` the heuristic backs off and the long-standing `force=False` default applies, since the gate already debounces. | A typical edge chain becomes: ``` camera_frame → call_model → detection_event_gate → timed_condition → send_alert ``` A `timed_condition` wired downstream of `call_model` *without* a trailing `send_alert` is now inert — the legacy implicit-alert path it used to gate is gone. The compiler surfaces a warning on the resulting compilation (the `/compile` API and `cyberwave workflow sync` preflight already render it) so the silent-skip case becomes visible instead of looking like a quietly broken alert chain. Existing workflows continue to load and run inference, but **stop emitting alerts** until you add the explicit chain — the migration is intentionally a hard break so silent regressions are impossible. ### Syncing to the edge Activating a `run_on_edge` workflow auto-publishes the `sync_workflows` MQTT command for each referenced twin, so the edge picks up the worker within seconds — no manual step. The editor locks the graph while active, so the natural edit flow (Deactivate → edit → Activate) republishes through the same signal. Reach for a manual sync only when the activation cycle can't fix it — e.g. a broker outage or Edge Core restart swallowed the original nudge. ```bash theme={null} # Interactive: picks the workflow, discovers target twins, sends sync via MQTT cyberwave workflow sync # Explicit cyberwave workflow sync # Or sync every workflow on a specific twin's edge cyberwave edge sync-workflows --twin-uuid ``` For programmatic recovery, two HTTP endpoints publish the same MQTT command: * `POST /api/v1/workflows/{uuid}/sync-edge` — per-workflow fan-out across all referenced twins. Returns `{success, workflow_uuid, command, twin_uuids[], request_ids, skipped_reason}`. `200` covers both the success case and declarative no-ops (cloud-only workflows, workflows without a twin-bound node, references that have all gone stale or cross-workspace) — `skipped_reason` pins the case. Partial broker failures also stay on `200` with `skipped_reason: "MQTT publish failed for N of M twins"`. Total broker failure surfaces as `500` so retry/back-off logic can branch on status code rather than parsing the body. * `POST /api/v1/twins/{uuid}/sync-workflows` — twin-wide republish covering every active workflow on that twin's edge. Surfaced in the dashboard as the twin editor's **Force-sync all workflows** menu item. All five entry points (CLI workflow sync, CLI edge sync-workflows, `/workflows/{uuid}/sync-edge`, `/twins/{uuid}/sync-workflows`, twin editor menu) publish the identical MQTT command on `cyberwave/twin/{twin_uuid}/command`, which makes Edge Core run `reconcile_worker_sync` immediately instead of waiting for the next periodic cycle. The CLI derives the MQTT topic prefix (`dev`, `staging`, empty for production) from `CYBERWAVE_ENVIRONMENT`/credentials and cross-checks it against the broker host before publishing. A mismatch (e.g. dev broker with production prefix) aborts with a clear error instead of silently shipping the command into a topic Edge Core never subscribed to. Override with `CYBERWAVE_MQTT_TOPIC_PREFIX` if you really need to. The edge device also syncs automatically on boot and periodically (default \~5 min, configurable via `CYBERWAVE_WORKER_SYNC_INTERVAL_LOOPS`). *** ## Execution Modes Workflows can be triggered by: | Trigger | Description | | ---------------- | --------------------------------------------- | | **Manual** | Run on demand from the dashboard or SDK | | **Schedule** | Run at specific times (cron) | | **Events** | Run when sensor data matches conditions | | **API** | Trigger from external systems via REST or MCP | | **Camera Frame** | Run on every camera frame at the edge device | *** ## Monitoring Executions Track workflow execution status and results: ```python theme={null} runs = cw.workflow_runs.list(workflow_id="workflow-uuid") for run in runs: print(f"Status: {run.status}, Started: {run.started_at}") ``` Each execution tracks status at both the workflow level and individual node level, including `started_at`, `finished_at`, and `error_message` fields. ### Check if a Workflow is Running Use `is_running()` to quickly check if a workflow has any active execution without manually querying runs: ```python theme={null} wf = cw.workflows.get("workflow-uuid") if wf.is_running(): print("Workflow is currently executing") ``` This returns `True` when any run has status `running`, `waiting`, or `requested`. In the dashboard, a **Running** indicator appears next to the Active badge in the workflow editor header whenever the workflow has an active execution. It refreshes automatically every 2 seconds. ### Why a run is queued A run on an edge workflow starts as `requested` (shown as **Requested**) and becomes `running` only once the edge acknowledges it. If the edge is still bringing its worker up — downloading the worker image, installing it, then loading and warming up models — the run carries a `pending_reason` explaining what it is waiting for, with a percentage where one is available: ```json theme={null} { "status": "requested", "pending_reason": { "reason": "worker_starting", "message": "Downloading the worker image", "progress_percent": 43 } } ``` `reason` is `worker_starting` when the edge is bringing the worker up, or `awaiting_edge` when the run has been sent but nothing has picked it up yet. The field is `null` on runs that are not waiting on an edge. The reason covers the worker's whole startup, including the models loading and warming up inside an already-started container — on a cold device the longest part of the wait. A run is not failed while the device is still reporting progress, and a run that the device picks up late is returned to **Running** rather than left marked failed. ### Concurrent run controls Open **Workflow run settings** from the gear icon in the workflow editor header to control overlapping runs: * **Allow concurrent runs of this workflow** is off by default. While off, a trigger is rejected with HTTP `409` whenever the same workflow already has a `requested`, `running`, or `waiting` execution. * **Incompatible workflows** selects other workflows from the same environment. The current workflow cannot start while any selected workflow has an in-flight execution. The off-by-default setting applies only to workflows created after this feature is deployed. Workflows that already existed are left with **Allow concurrent runs of this workflow** on, so their behavior does not change; their authors must turn it **off** to adopt serialization. Refused automatic triggers are skipped, rather than queued for later execution. These settings apply to cloud-dispatched manual and REST triggers, schedules, webhooks, inbound email, MQTT and alert triggers, and partner integrations. They do not prevent independently started edge runs; reports from runs already underway are always retained so their progress remains visible. The REST fields are `allow_concurrent_executions` and `concurrency_blocked_by_workflow_uuids` on workflow create, update, and response payloads. *** ## Example: Edge Detection Workflow A camera\_frame workflow that runs YOLO on the edge and emits alerts: ```mermaid theme={null} flowchart LR A[Camera Frame Trigger] --> B[Call Model: YOLOv8] B --> C{Detection?} C -->|Yes| D[Publish Event] C -->|No| E[Skip] ``` *** ## Best Practices * **Keep workflows focused** — create separate workflows for distinct operations rather than one large workflow. This makes debugging and maintenance easier. * **Add error handling** — include condition nodes to handle failure cases gracefully. Consider what should happen if a joint can't reach its target. * **Use meaningful names** — name nodes and workflows descriptively. "Alert on person in zone A" is better than "Node 1". * **Use `on_enter` emit mode for alerts** — avoids flooding with repeated events while the same object stays in frame. * **Set appropriate cooldowns** — balance between responsiveness and event volume. 5s is a safe default; lower for time-critical use cases. * **Eject before customising** — never edit `wf_*.py` files directly. Copy them to a custom name and deactivate the originating workflow. *** ## Environment-bound workflows A workflow can optionally be bound to an environment (set `environment_uuid` when creating it, or open the *Create Environment Workflow* dialog from an environment panel). Bound workflows are scoped to that environment in the editor, surface in the environment's workflow list, and ship to the environment's edges through `edge_sync_workflows` when combined with `run_on_edge: true`. Compiler dispatch keys off the graph itself: a `twin_control` node renders through the navigation path and a `camera_frame` trigger renders through the perception path, regardless of how the workflow is bound. Run `cyberwave workflow compile ` to see exactly which path the unified compiler took, or the diagnostic explaining why it skipped the workflow. *** ## Code node The **Code** action node runs a user-supplied Python function on the edge. It is only valid on workflows with `run_on_edge: true` — Cyberwave never executes user-authored code on its own infrastructure. * **Runtime**: Python, on the edge worker container that already runs the compiled `wf_*.py` module. * **I/O contract**: Every Code node must define a top-level `def run(input: dict) -> dict`. The return value is fed into the next Code node's `input` via an internal `_node_output` variable. * **Validation**: The API parses the body with `ast.parse` on create/update and rejects syntax errors or missing `run` functions inline, before activation. * **Activation guards**: Activating a workflow is blocked if it contains a Code node and either (a) `run_on_edge` is false, or (b) the workflow uses a `camera_frame` trigger (not yet supported by the perception path of the edge compiler). * **Availability**: The node is always visible in the palette; it is disabled with an "Available only on run\_on\_edge workflows" tooltip when the workflow is not edge-bound. ## Workflow assistant Select a workflow in the workbench, then use **Prompt** or the right-hand **Assistant** tab to edit it with the assistant. Click the assistant title in **Assistant** to switch between **Environment assistant** and **Workflow assistant**. When the workbench is closed, the workflow option is disabled and reads **Open the workbench**. The workbench shows node details only while a node inspector is open. Close it or clear the node selection to reclaim that space. ## Edge voice workflows (audio + STT + control) Voice pipelines chain **Audio Track**, **Audio Assistant**, **Wake Word Engine**, **Call Model** (STT), **Fuzzy Matcher**, **Twin**, and **Virtual Controller**. Each node declares a minimal Python/SDK extra; the compile server validates imports before shipping `wf_*.py`. See **[Edge workflow dependencies](/feature-reference/workflows/edge-dependencies)** for the full matrix (compile server `base.txt`, edge worker extras, catalog STT models). | Doc | Topic | | -------------------------------------------------------------------------- | ------------------------------------ | | [Audio in Workflows](/feature-reference/workflows/audio-in-workflows) | PCM format, pipeline, compile checks | | [Call Model STT on edge](/feature-reference/workflows/call-model-stt-edge) | Whisper.cpp vs Faster Whisper | | [Fuzzy Matcher](/feature-reference/workflows/fuzzy-matcher) | Command matching after STT | | [Twin](/feature-reference/workflows/twin) | Twin + policy outputs → candidates | | [Virtual Controller](/feature-reference/workflows/virtual-controller) | MQTT dispatch | *** # Anonymize node Source: https://docs.cyberwave.com/feature-reference/workflows/anonymize-image Obscure detected people, vehicles or other objects in workflow images or live edge frames: pixelate, blur, redact or fill. `anonymize` is a workflow node that de-identifies detected regions in an image or camera frame. It is the destructive counterpart to [`annotate`](./overview): where `annotate` draws *on top of* preserved pixels, `anonymize` replaces pixels in each detection region with a mosaic, blur, redaction grid, or solid fill, producing a frame safe to publish to downstream consumers. Execution context is inferred from the upstream graph: * Wired downstream of a `camera_frame` trigger + `call_model` chain it is compiled into the edge worker and processes the live frame. * Wired anywhere else it runs in the cloud workflow runner against an image URL. Typical chain: ``` trigger → call_model → anonymize → annotate → update_attachment ``` Order matters: anonymise first, annotate second. Reversing would pixelate over the drawn boxes. On the edge side the codegen normalises this ordering automatically regardless of graph order. ## Modes | Mode | Description | Reversibility | | -------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | `pixelate` (default) | Adaptive mosaic (\~24 blocks across the short side). Preserves silhouette and motion. | Reversible by public depixelation models — use for casual obscuring only. | | `blur` | Heavy Gaussian blur (kernel 99, clamped to the region). | Hard to invert but not impossible with strong blur. | | `redact` | Solid fill with a visible grid, "censored document" look. Destroys source pixels. | Irreversible (pixels replaced). | | `bbox` | Solid colour fill. Bluntest option. | Irreversible. | ## Inputs | Field | Type | Description | | ---------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `image_bytes` | object | Raw image bytes to anonymise. Wire from `data_source.image_bytes` or any upstream node that emits bytes. Required on cloud chains; on edge camera-frame chains the worker passes the upstream frame straight in. | | `image_url` | image | Optional echo only — used as the value of `source_image_url` in the output. Bytes always come from `image_bytes`. | | `detections` | array | Detection array from an upstream `call_model`. Same formats as `annotate` (Gemini 0-1000, normalized 0-1, pixel `xywh`, pixel `xyxy`). Required. | | `mode` | string | `pixelate` (default), `blur`, `redact`, or `bbox`. | | `target_classes` | array | Detection labels to obscure (default `["person"]`). Other labels pass through untouched. Empty array obscures every detection. Authored via the dedicated chip editor in the Anonymize inspector — writes `parameters.target_classes`. | | `pixel_size` | number | Optional mosaic block size for `pixelate` / `redact`. Defaults to an adaptive per-region value. | | `confidence_threshold` | number | Skip detections scoring below this (`0.0`–`1.0`, default `0.0` = no filtering). Matches the knob on `annotate` for composable chains. | ## Outputs Cloud chains populate the output fields below. Edge chains publish the filtered frame directly to the camera driver's frame-filter channel without writing to the node output dict — the workflow inspector shows these fields as `cloud_only` to make that explicit. | Field | Type | Description | | ------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `anonymized_image_bytes` | object | Raw bytes of the anonymised image, re-encoded in the source format (JPEG / PNG). Canonical handoff — wire a downstream node's `image_bytes` to this field via the InputMappingEditor. | | `anonymized_image_base64` | image | Data URL (`data:image/...;base64,...`) of the anonymised image. UI preview channel — consumed by the workflow run-history thumbnail. Preserves the source MIME type, falling back to PNG when the source format can't be detected — echoing a 100 KB JPEG back as a megabyte PNG data-URL would balloon downstream storage. | | `source_image_url` | image | Original input URL. | | `detection_count` | number | Number of detection regions obscured. | ## Edge implementation When compiled to the edge, `anonymize` uses [`cyberwave.vision.blank_persons`](https://github.com/cyberwave-os/cyberwave/blob/dev/cyberwave-sdks/cyberwave-python/cyberwave/vision/anonymize.py) from the Cyberwave Python SDK. The cloud and edge paths share the same pixel-level algorithm and emit byte-for-byte identical output for the same input frame + detections. ### Privacy fail-closed gate `blank_persons` only obscures bounding-box regions for detections in the active `target_classes` set. On a frame where the model returns *zero* matching detections (sub-threshold confidence, occluded subject, partial body, transient miss) the helper returns the input frame untouched. To prevent that frame from being published to [`FILTERED_FRAME_CHANNEL`](../../edge/drivers/frame-filters) and silently substituted into the WebRTC stream, the generated edge worker wraps the publish: ```python theme={null} if any(d.label in {'person'} for d in results.detections): cw.data.publish(FILTERED_FRAME_CHANNEL, _frame, twin_uuid=...) else: cw.data.publish(FILTERED_FRAME_CHANNEL, np.zeros_like(frame), twin_uuid=...) ``` A missed detection therefore becomes an explicit black frame rather than a raw passthrough — matching the camera driver's existing fail-closed behaviour for stale and shape-mismatched filtered frames. When multiple `anonymize` nodes are chained, the gate uses the **union** of every node's `target_classes`. An anonymize node authored with an empty `target_classes` list is treated as a privacy lockdown — the gate becomes `set()` so every frame is replaced with black. `annotate`-only chains have no privacy contract and remain un-gated: boxes drawn over a raw frame is the intended output. ## Privacy caveat These helpers are designed for casual visual obscuring, not as a cryptographic de-identification primitive: * `pixelate` is reversible by public depixelation models, especially at the default block density. * `blur` with the default kernel is much harder to invert but not impossible. * `bbox` and `redact` destroy the underlying pixel information (the output contains only the solid fill + grid lines). Prefer `redact` when you want the destruction to *look* deliberate (audit trails, public release), `bbox` when you want a clean uniform mask. For GDPR-grade de-identification, combine with format-shifting (publish only detection events, not frames) or run the obscured frame through a second irreversible transform. # Audio Assistant Source: https://docs.cyberwave.com/feature-reference/workflows/audio-assistant/overview Speech segmentation with Voice Assistant (VA) and acoustic event detection with Sound Security Guard (SSG) for edge audio workflows. The **Audio Assistant** node sits between an [Audio Track](/feature-reference/workflows/audio-track/overview) trigger and downstream nodes (STT, alerts, models). It normalizes all input to **PCM S16LE int16 @ 16 kHz mono** via the shared audio ingress layer—the same contract as the rest of the audio pipeline. ## Pipeline position ``` Audio Track Trigger → Audio Assistant → Call Model / Send Alert / … ``` ## Modalities | Modality | Purpose | Engine | | ------------------------------ | --------------------------------------- | ------------------ | | **Voice Assistant (VA)** | Segment speech utterances | Silero VAD | | **Sound Security Guard (SSG)** | Detect security-related acoustic events | MIT AST (AudioSet) | Only one modality is active per node instance. ## Shared audio contract | Direction | Key | Format | | --------- | ---------------- | ---------------------------------------------------------------------------------- | | Input | `audio` | PCM S16LE numpy `int16`, float32, raw bytes, or WAV—adapted to int16 @ 16 kHz mono | | Output | `audio` | int16 mono @ 16 kHz (when a segment or alert window is emitted) | | Output | `sample_rate_hz` | Always `16000` | | Output | `channels` | Always `1` | Upstream **Audio Track** buffer presets control chunk size into the node: | Preset | Chunk size | Typical use | | ----------------------- | ------------- | ---------------------------------------- | | Voice Assistant (32 ms) | 512 samples | VA streaming (matches Silero frame size) | | Wake Word (80 ms) | 1280 samples | Wake Word Engine | | Speech-To-Text (4 s) | 64000 samples | Batch / long windows | For **SSG**, prefer accumulating at least **1–4 s** per analysis window (default analysis preset: Speech-To-Text 4 s). ## Edge execution Audio Assistant nodes are **edge-only**. Workflows compile to a `wf_*.py` worker module and sync to the device: ```bash theme={null} cyberwave workflow compile # inspect emitted source + warnings cyberwave workflow sync # deploy to edge ``` Typical chain: ``` Audio Track (@cw.on_audio) → Audio Assistant → Send Alert / Call Model ``` Compile checks: * **VA** upstream Audio Track must use buffer preset **Voice Assistant (32 ms)**. * **SSG** upstream Audio Track should use **Speech-To-Text (4 s)** (or custom ≥1 s). The compiler emits a warning listing required Python extras when VA/SSG nodes are present. ## Edge dependencies ```bash theme={null} pip install "cyberwave[ml-vad]" # Voice Assistant (Silero) pip install "cyberwave[ml-aed]" # Sound Security Guard (transformers + AST) ``` The **edge-ml-worker** container image pre-installs `zenoh`, `ml-vad`, `ml-aed`, and `ml-wakeword`, and pre-downloads AST and OpenWakeWord weights for air-gapped use. SSG on bare-metal edges downloads `MIT/ast-finetuned-audioset-10-10-0.4593` on first run (\~340 MB) unless baked into the image. ## Pages * [Voice Assistant (VAD)](/feature-reference/workflows/audio-assistant/voice-assistant) * [Sound Security Guard (AED)](/feature-reference/workflows/audio-assistant/sound-security-guard) * [Technical reference](/feature-reference/workflows/audio-assistant/technical-reference) # Sound Security Guard (SSG) Source: https://docs.cyberwave.com/feature-reference/workflows/audio-assistant/sound-security-guard AST-based acoustic event detection for security and safety monitoring. **Sound Security Guard** monitors audio for a **single active scenario** at a time using the pretrained [Audio Spectrogram Transformer](https://huggingface.co/MIT/ast-finetuned-audioset-10-10-0.4593) (`MIT/ast-finetuned-audioset-10-10-0.4593`). The model outputs 527 AudioSet class probabilities (multi-label sigmoid). No fine-tuning is required—scenarios map to existing AudioSet label strings. ## Strict scenario isolation Only labels belonging to the selected scenario are evaluated. For example, with **Glass Break** active, a passing police siren is ignored even if the model detects it strongly. ## Scenarios (sub-modalities) | Scenario | Monitored AudioSet labels (substring match) | | --------------------------------- | ------------------------------------------------------------------------------ | | **Glass Break / Falling Objects** | Glass, Shatter, Smash crash, Thump, Crash, Bang | | **Constant Alarm (Siren)** | Alarm, Car alarm, Smoke detector, Siren, Ambulance (siren), Police car (siren) | | **Help! / Screaming** | Screaming, Yell, Shout, Children shouting | | **Custom** | User-defined comma-separated label substrings | ## Parameters | Parameter | Default | Description | | ---------------------- | ---------------- | ------------------------------------------------------ | | `confidence_threshold` | `0.40` | Alert when any scenario label exceeds this probability | | `output_buffer_preset` | `speech-to-text` | Analysis window size (4 s recommended) | | `output_buffer_size_s` | `4.0` | Custom window length (seconds, min 1 s) | | `event_cooldown_s` | `5.0` | Minimum seconds between alerts | ## Input / output **Input:** Same as VA—`audio` adapted to PCM S16LE int16 @ 16 kHz mono. **Interim output (window filling / no alert):** ```json theme={null} { "event_detected": false, "event_confidence": 0.12, "event_label": "", "event_type": "glass_break", "active_scenario": "glass_break", "sample_rate_hz": 16000, "channels": 1 } ``` **Alert output:** ```json theme={null} { "audio": "", "event_detected": true, "event_confidence": 0.67, "event_label": "Glass", "event_type": "glass_break", "active_scenario": "glass_break", "start_timestamp_sec": 8.0, "end_timestamp_sec": 12.0, "sample_rate_hz": 16000, "channels": 1 } ``` Wire `event_detected` to a `send_alert` node or conditional gate (see [Alerts](/feature-reference/edge/drivers/alerts)). ## Analysis window Audio accumulates until the analysis window is full (default **4 s**), then AST runs inference. The buffer advances by **50% hop** (half-window overlap) so events near window boundaries are not missed. After an alert, a **cooldown** suppresses duplicate notifications. ## Example workflow ``` Audio Track → Audio Assistant (SSG, glass_break) → Send Alert ``` ## Edge install ```bash theme={null} pip install "cyberwave[ml-aed]" ``` First inference downloads the AST weights from Hugging Face. # Audio assistant technical reference Source: https://docs.cyberwave.com/feature-reference/workflows/audio-assistant/technical-reference Audio Assistant I/O schema, buffering, and runtime architecture. ## Node inputs (configuration) Stored in `node.parameters` unless wired from upstream: | Field | VA | SSG | Description | | ---------------------- | -- | --- | -------------------------------------------- | | `modality` | ✓ | ✓ | `voice_assistant` or `sound_security_guard` | | `sub_modality` | ✓ | ✓ | VAD profile or security scenario | | `vad_*` | ✓ | — | Silero thresholds (advanced) | | `output_buffer_preset` | ✓ | ✓ | VA: output re-chunking; SSG: analysis window | | `output_buffer_size_s` | ✓ | ✓ | Custom buffer/window seconds | | `confidence_threshold` | — | ✓ | SSG alert threshold (0–1) | | `event_cooldown_s` | — | ✓ | SSG seconds between alerts | | `custom_event_labels` | — | ✓ | SSG custom scenario label list | Runtime audio is resolved automatically from upstream `audio` via `_CwAudioIngress` (no manual `sample_rate_hz` input). ## VA outputs | Output | Type | When emitted | | --------------------- | --------------------------- | ----------------------- | | `audio` | AUDIO (int16 @ 16 kHz mono) | Speech segment complete | | `speech_probability` | NUMBER | Every chunk | | `is_speaking` | BOOLEAN | Every chunk | | `start_timestamp_sec` | NUMBER | With `audio` | | `end_timestamp_sec` | NUMBER | With `audio` | | `sample_rate_hz` | NUMBER | Always `16000` | | `channels` | NUMBER | Always `1` | ## SSG outputs | Output | Type | When emitted | | --------------------- | ------- | --------------------------------- | | `audio` | AUDIO | Alert fired (analysis window) | | `event_detected` | BOOLEAN | Every chunk | | `event_confidence` | NUMBER | Every chunk (best scenario match) | | `event_label` | STRING | Best matching AudioSet label | | `event_type` | STRING | Active scenario key | | `active_scenario` | STRING | Same as `event_type` | | `start_timestamp_sec` | NUMBER | With alert | | `end_timestamp_sec` | NUMBER | With alert | | `sample_rate_hz` | NUMBER | Always `16000` | | `channels` | NUMBER | Always `1` | ## Audio ingress (shared) All modalities use `_CwAudioIngress.adapt_safe()`: * **Canonical format:** numpy `int16`, 16000 Hz, mono, key `audio` * **Accepted inputs:** int16/float32 numpy, raw PCM bytes, WAV bytes * **Passthrough:** int16 @ 16 kHz mono is zero-copy ## VA architecture `_CwAudioStreamProcessor` + Silero `VADIterator`: 1. Incoming chunks reframed to **512 samples** (32 ms @ 16 kHz) 2. Ring buffer stores float32 audio; indices from VAD mark utterance bounds 3. On speech end: slice buffer → int16 segment → emit ## SSG architecture `_CwAaAstGuard` + Hugging Face AST: 1. Accumulate int16 chunks until `window_samples` (from buffer preset, default 4 s) 2. Convert to float32, run `ASTFeatureExtractor` + `ASTForAudioClassification` 3. Multi-label sigmoid over 527 classes; filter by active scenario labels only 4. If `max(matching_probs) >= confidence_threshold` → emit alert + audio window 5. Slide buffer by `hop_samples` (50% overlap); enforce `event_cooldown_s` ### Model * **ID:** `MIT/ast-finetuned-audioset-10-10-0.4593` * **Training:** AudioSet (527 classes) * **Inference:** `torch.sigmoid(logits)` per class ### Scenario label maps (built-in) ```text theme={null} glass_break → Glass, Shatter, Smash crash, Thump, Crash, Bang constant_alarm → Alarm, Car alarm, Smoke detector, Siren, … screaming → Screaming, Yell, Shout, Children shouting custom → user-provided substrings ``` Matching is case-insensitive substring: `target in class_label.lower()`. ## Buffer presets (shared field) | Preset | Seconds | Samples @ 16 kHz | Typical modality | | ---------------- | ---------------------- | ---------------- | ----------------------------------------------- | | `none` | — | — | VA: full utterance | | `wake-word` | 0.08 | 1280 | VA downstream / not recommended for SSG | | `speech-to-text` | 4.0 | 64000 | VA STT chunks / **SSG default analysis window** | | `custom` | `output_buffer_size_s` | — | User-defined | SSG enforces a minimum analysis window of **1.0 s**. ## Alert attribution On SSG alert, `_source_summary` includes `kind: audio_assistant`, `modality: sound_security_guard`, `sub_modality`, `event_label`, and `event_confidence` for Send Alert `source_chain` metadata. ## Edge cases | Case | Behavior | | ------------------------------ | --------------------------------------------- | | Empty audio chunk | Skipped | | SSG during cooldown | Analysis skipped until cooldown expires | | Custom scenario with no labels | No matches; never alerts | | Upstream non-16 kHz | Resampled by audio ingress | | VA oversized chunks | Reframed to 512 samples with one-time warning | # Voice Assistant (VA) Source: https://docs.cyberwave.com/feature-reference/workflows/audio-assistant/voice-assistant Silero VAD profiles for real-time and batch speech segmentation. **Voice Assistant** uses [Silero VAD](https://github.com/snakers4/silero-vad) to detect speech start/end, extract utterances, and optionally re-chunk output for downstream nodes. ## Sub-modality profiles | Profile | Use case | | ----------------------------- | ----------------------------------------------------- | | **Real-Time Voice Assistant** | Low-latency conversational / command endpoints | | **High-Noise / Industrial** | Factory floors, vehicles, call centres | | **Batch Transcription / STT** | Offline Whisper-style segmentation (\~28 s max chunk) | | **Quiet Studio / Whisperer** | Distant mic, soft speech, long pauses | | **Custom** | Manual Silero parameters | ## Input / output **Input:** `audio` from Audio Track (any supported encoding; adapted to int16 @ 16 kHz mono). **Outputs (every chunk while listening):** ```json theme={null} { "speech_probability": 0.87, "is_speaking": true, "sample_rate_hz": 16000, "channels": 1 } ``` **Outputs (when speech ends):** ```json theme={null} { "audio": "", "speech_probability": 0.92, "is_speaking": false, "start_timestamp_sec": 1.2, "end_timestamp_sec": 3.8, "sample_rate_hz": 16000, "channels": 1 } ``` ## Output buffer preset (optional) After a full utterance is detected, audio can be re-chunked for downstream consumers: | Preset | Duration | Samples @ 16 kHz | | ---------------- | ------------ | ---------------- | | None | Full segment | — | | Wake Word Engine | 80 ms | 1280 | | Speech-To-Text | 4 s | 64000 | | Custom | User-defined | — | ## Recommended Audio Track preset Set the upstream Audio Track **buffer preset** to **Voice Assistant (32 ms)** so chunks are 512 samples—the native Silero frame size. Larger chunks still work (the node reframes internally) but add latency. # Audio in workflows Source: https://docs.cyberwave.com/feature-reference/workflows/audio-in-workflows How audio transmission, encoding, and format adaptation works across workflow nodes All Cyberwave audio workflow nodes share a **standard audio format** for inter-node communication. This page explains the format, how nodes adapt incoming audio, and best practices for building audio pipelines. ## Standard Audio Format Every audio node in a workflow produces and consumes audio using: | Property | Value | | --------------- | --------------------------------------- | | **Container** | NumPy array (`dtype=int16`) | | **Encoding** | PCM S16LE (signed 16-bit little-endian) | | **Sample Rate** | 16,000 Hz | | **Channels** | 1 (mono) | | **Key name** | `audio` | This is raw 16-bit PCM — the same encoding used by telephony systems, Whisper, Silero VAD, and OpenWakeWord. No compression, no container overhead. ## Why This Format * **Zero-copy between nodes**: NumPy int16 arrays are passed by reference. A 10-second buffer (320,000 bytes) moves between nodes as a lightweight pointer — no data duplication. * **Universal compatibility**: Every speech model (Whisper, Silero, OpenWakeWord) works natively at 16 kHz int16 mono. * **Minimal latency**: No encoding/decoding step between nodes. ## Automatic Format Adaptation Every audio node includes an **ingress adapter** that automatically handles incoming audio regardless of format: | Incoming Format | What Happens | Performance | | ------------------------- | ----------------------------------------- | ----------- | | int16 numpy, 16 kHz, mono | **Zero-copy passthrough** (same object) | Fastest | | int16 numpy, other rate | Resampled to 16 kHz | Fast | | int16 numpy, stereo | Downmixed to mono | Fast | | float32 numpy | Scaled to int16 (`× 32768`) | Fast | | WAV bytes (RIFF header) | Parsed, decoded, resampled if needed | Moderate | | Raw PCM bytes (no header) | Interpreted as int16, resampled if needed | Fast | If the format cannot be adapted (e.g. compressed MP3 bytes without a decoder), the node publishes a **human-readable alert** explaining what was received and what was expected. ## Metadata Alongside Audio Audio is never passed as a naked array. Every node outputs a **dictionary** with the audio and its metadata: ```python theme={null} { "audio": numpy_int16_array, # the PCM data (zero-copy reference) "sample_rate_hz": 16000, # always 16 kHz after normalization "channels": 1, # always mono after downmix "speech_probability": 0.87, # VAD confidence (Audio Assistant only) "is_speaking": True, # speech state flag "start_timestamp_sec": 1.2, # segment boundary (when available) "end_timestamp_sec": 3.8, # segment boundary (when available) } ``` This means downstream nodes always know the sample rate, channel count, and timing of what they receive — even in buffer/chunk streaming scenarios. ## The Audio Pipeline A typical audio-to-text pipeline: ``` Microphone → Audio Track → Audio Assistant (VAD) → Wake Word Engine → Call Model (Whisper) → text ``` ### What each node does: 1. **Audio Track** — Receives raw 20 ms chunks from the edge microphone via Zenoh. Accumulates them in a FIFO buffer and emits when the buffer is full. Normalizes to int16 @ 16 kHz mono. Buffer presets: * `voice-assistant`: 512 samples (32 ms) — for Audio Assistant / Silero VAD * `wake-word`: 1,280 samples (80 ms) — matches OpenWakeWord's internal frame size * `speech-to-text`: 64,000 samples (4 s) — for direct STT input * `custom`: user-defined duration in seconds Outputs the buffered audio via the `audio` key plus metadata (`sample_rate_hz`, `channels`, `duration_s`, `sample_count`). 2. **Audio Assistant** — Runs Silero VAD on the continuous stream. Produces **two signals on every chunk**: * `speech_probability` (float 0.0-1.0): The raw VAD confidence — a continuous trigger/logic gate * `audio` (int16 numpy): Only emitted when a complete speech segment is detected (speech end) This dual-output design means downstream nodes can react to the VAD trigger immediately, without waiting for the full segment extraction. Optionally, the **Output Buffer Preset** re-chunks the extracted speech into fixed-size frames for downstream consumption: * `wake-word`: 1,280 samples (80 ms) — for feeding a Wake Word Engine * `speech-to-text`: 64,000 samples (4 s) — for Whisper/STT models * `custom`: user-defined buffer size in seconds * `none` (default): pass the full speech segment as-is 3. **Wake Word Engine** — Listens for a configurable trigger phrase using [OpenWakeWord](https://github.com/dscripka/openWakeWord). Users select one or more pre-trained models (`alexa`, `hey_mycroft`, `hey_jarvis`, `hey_rhasspy`, `weather`, `timer`) from a searchable multi-select — the engine activates on any of them when that model’s score ≥ a single **Detection Threshold** (default **0.5** for all models). Custom `.onnx` model support is coming soon. Pre-trained models are downloaded automatically on the edge device via `openwakeword.utils.download_models()`. Accepts PCM arrays, raw bytes, WAV bytes, or WAV file paths as input. Internally buffers input into exact 80 ms (1280-sample) frames for optimal openWakeWord prediction accuracy. After detection, streams **fixed-size audio chunks** to downstream nodes until silence is detected. Output chunk size is configurable: * `voice-assistant` preset: 512 samples (32 ms) — for feeding another VAD stage * `wake-word` preset: 1,280 samples (80 ms) — openWakeWord native frame * `speech-to-text` preset: 64,000 samples (4 s) — optimized for Whisper/STT * Default output preset is `wake-word` (80 ms); use `speech-to-text` when Whisper follows * `custom` preset: user-defined buffer size in seconds One command-only `audio` buffer is emitted per wake session (wake phrase trimmed via **Wake Word Trim**). Wire Call Model STT to the `audio` output. **Input validation**: The Wake Word Engine validates that its audio input meets openWakeWord requirements (16 kHz, int16/float32, mono, raw PCM). If the upstream audio cannot be adapted to meet these specs, the node raises an error with a detailed explanation. 4. **Call Model (Whisper)** — Receives int16 audio, passes it (with `sample_rate_hz` and `channels` metadata) to the model's `predict()` function. Outputs the transcription as a string. ### Voice → robot command (optional tail) After STT, add controller-aware matching and MQTT dispatch: ``` call_model.result → fuzzy_matcher.query (Uncertain String) twin.control_actuations (or control_labels) → fuzzy_matcher.candidates (Source of Truth: string or array) fuzzy_matcher.match_string → virtual_controller.command ``` | Node | Role | | ---------------------- | ---------------------------------------------------------------------------------------------- | | **Twin** | Same twin as Virtual Controller; exposes valid commands from assigned policy | | **Fuzzy Matcher** | Maps the uncertain string to the best source-of-truth entry (`match`, `match_string`, `score`) | | **Virtual Controller** | Resolves label/actuation and publishes `cyberwave/twin/{uuid}/command` | Branch on `fuzzy_matcher.match` with **Conditional** before Virtual Controller so unrelated speech does not dispatch commands. See [Fuzzy Matcher](/feature-reference/workflows/fuzzy-matcher) and [Virtual Controller](/feature-reference/workflows/virtual-controller). ### ML model environment Call Model nodes receive both the audio array and its metadata. The model's predict call always knows the format: ```python theme={null} model.predict(audio_int16, sample_rate_hz=16000, channels=1, twin_uuid="...") ``` For cloud APIs that require WAV, the ingress adapter automatically converts int16 to WAV bytes before upload. ## Connecting Nodes All audio nodes use the **same `audio` key** for input and output. In the workflow editor, you simply connect one node's output to the next node's input — no format configuration needed. ``` Node A [audio] ──→ [audio] Node B [audio] ──→ [audio] Node C ``` The nodes handle format adaptation internally. You never need to insert format conversion nodes or configure sample rates manually. ## Compile-Time Validation When you compile a workflow for edge (`run_on_edge: true`), the Django **compile server** imports the libraries each node needs and fails with an actionable message if a package is missing (same pattern as Wake Word Engine). | Node / model | Compile-server packages | | --------------------------- | --------------------------------- | | Wake Word Engine | `openwakeword`, `onnxruntime` | | Fuzzy Matcher | `rapidfuzz` | | Audio Assistant | `silero-vad` (+ torch transitive) | | Call Model — whisper.cpp | `pywhispercpp` | | Call Model — faster-whisper | `faster-whisper` | | Twin / Virtual Controller | `httpx`, `paho-mqtt` (base deps) | | Audio Track | no ML import at compile | Packages live in `cyberwave-backend/requirements/base.txt`. Rebuild the Django image after changes. Full tables, SDK extras, and slim worker builds: **[Edge workflow dependencies](/feature-reference/workflows/edge-dependencies)**. The assembler also validates that audio-consuming nodes have an audio-producing upstream and that the chain is topologically valid. ## Supported Input Formats (per node) Every audio node accepts these formats as input: | Format | Example Source | | ------------- | ----------------------------------------- | | NumPy int16 | Audio Track output, other audio nodes | | NumPy float32 | Custom code nodes, ML model outputs | | WAV bytes | File uploads, cloud API responses | | Raw PCM bytes | WebSocket streams, raw microphone drivers | ## Error Handling When a node receives audio it cannot process: 1. **Logs an error** with format details (detected type, rate, channels) 2. **Publishes an alert** to the twin (`alert_type='audio_format_incompatible'`) visible in the Cyberwave UI 3. **Skips the frame** gracefully — the workflow continues with the next chunk No crashes. No silent failures. ## Performance Notes * **Zero-copy is the fast path**: When the upstream node outputs int16 @ 16 kHz mono (the standard), downstream nodes receive the exact same memory — no allocation, no copy. * **Avoid unnecessary WAV wrapping**: If your pipeline is fully edge-side, keep audio as int16 numpy throughout. Only convert to WAV when sending to external APIs. * **NumPy slicing is zero-copy too**: `audio[start:end]` creates a view, not a copy. The Wake Word Engine uses this for its lookback buffer. * **Buffered streaming**: The Wake Word Engine outputs fixed-size chunks (not one giant array). This keeps memory bounded and allows downstream STT to start processing immediately as chunks arrive. ## Edge dependencies Install SDK extras on the edge host (or `cyberwave-edge-core[...]` passthroughs). `edge-sync` returns `model_requirements` from node emitters and Call Model catalog metadata. | Node / model | `edge-sync` extra | Install | | ------------------------- | --------------------------- | --------------------------------------------------------------------- | | Audio Track | — | `cyberwave[zenoh]` on worker; `cyberwave[microphone]` on capture host | | Audio Assistant | `ml-audio` | `cyberwave[ml-audio]` | | Wake Word Engine | `ml-wakeword` | `cyberwave[ml-wakeword]` | | Fuzzy Matcher | `fuzzy-match` | `cyberwave[fuzzy-match]` | | Call Model STT | `ml-stt` or `ml-stt-faster` | Per [catalog model](/feature-reference/workflows/call-model-stt-edge) | | Twin / Virtual Controller | — | Base `cyberwave` (API + MQTT) | On Raspberry Pi, install **only** the extras your workflow uses — not `ml-all`. See **[Edge workflow dependencies](/feature-reference/workflows/edge-dependencies)**. ## Related Pages Compile server, SDK extras, STT catalog Whisper.cpp and Faster Whisper on edge Edge microphone trigger node VAD-powered speech segmentation Voice-activated trigger gate Read twin + controller policy for command candidates Map noisy STT text to command labels Dispatch matched commands to the twin over MQTT # Audio Track Source: https://docs.cyberwave.com/feature-reference/workflows/audio-track/overview Edge microphone trigger — stream PCM chunks into workflows via Zenoh. The **Audio Track** trigger fires for every buffered chunk from a twin's edge microphone. Audio is delivered over the Zenoh data bus and handled by `@cw.on_audio` in the compiled worker. ## Edge pipeline ``` Microphone driver → Zenoh → @cw.on_audio → Audio Track FIFO → downstream nodes ``` ## Buffer presets (downstream pairing) | Preset | Duration | Pair with | | ----------------------- | ------------- | ------------------------- | | Voice Assistant (32 ms) | 512 samples | Audio Assistant (VA) | | Wake Word (80 ms) | 1280 samples | Wake Word Engine (direct) | | Speech-To-Text (4 s) | 64000 samples | SSG, Whisper / STT | The compiler rejects incompatible pairings (e.g. 4 s chunks into Wake Word without VAD). ## Deploy ```bash theme={null} cyberwave workflow compile cyberwave workflow sync ``` ## Dependencies ```bash theme={null} pip install "cyberwave[zenoh]" # required for @cw.on_audio ``` Downstream nodes add `ml-vad`, `ml-aed`, or `ml-wakeword` as needed. See [feature reference](/feature-reference/workflows/audio-track/overview). # Barcode Reader node Source: https://docs.cyberwave.com/feature-reference/workflows/barcode-reader Decode 1D and 2D codes (QR, Data Matrix, EAN/UPC, Code 128 and more) with zxing-cpp, on edge camera frames or in the cloud workflow runner. `barcode_reader` is a stateless perception node that decodes barcodes and 2D codes from a frame and emits a structured list of codes plus a `call_model`-shaped `detections` projection — so the existing perception chain (`annotate`, `spatial_filter`, `conditional/detection_event_gate`, `send_alert`) consumes barcodes with no special-casing. The same node compiles into the edge worker (`@cw.on_frame` handler on the device) when the workflow has `Run on edge` enabled and a Camera Frame trigger upstream, **and** runs in the cloud workflow runner otherwise (against an `image_url` or `image_bytes` from `data_source` / `call_model`). The decode helpers live in `src/lib/workflow_utils.py` and are inlined into the generated worker via `inspect.getsource()` so the cloud and edge paths share one decoder implementation. It is backed by [zxing-cpp](https://github.com/zxing-cpp/zxing-cpp) (Apache-2.0), a fast native-C++ decoder with prebuilt Python wheels for `manylinux_x86_64`, `manylinux_aarch64` (Pi 4 / 5 64-bit), macOS, and Windows. No GPU and no system package install — `pip install zxing-cpp` inside the edge worker image is enough. Typical chain for a "scan and alert" warehouse workflow: ``` trigger (camera_frame) → barcode_reader → conditional → send_alert ↘ annotate (overlay boxes for the live preview) ``` ## Symbologies Default is "any symbology zxing-cpp supports". You can narrow it down to the formats you actually expect — this reduces false positives and shortens decode time per frame. | Group | Formats | | ---------------------- | ----------------------------------------------------------------------------- | | Retail | EAN-13, EAN-8, UPC-A, UPC-E | | Logistics / industrial | Code 128, Code 39, Code 93, ITF, Codabar, GS1 DataBar, GS1 DataBar Expanded | | 2D | QR Code, Micro QR, Rectangular Micro QR, Data Matrix, Aztec, PDF417, MaxiCode | ## Inputs | Field | Type | Description | | --------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `frame` | image / bytes | Canonical input. On edge, implicitly wired from an upstream `camera_frame` trigger (decoded ndarray). On cloud, typically auto-wired from `Data Source.image_bytes` — Data Source eager-fetches the URL for every `data_type` so the bytes are always populated. | | `image_bytes` | bytes | Legacy alias for callers without input mappings. Cloud-only. Remote URL inputs are no longer accepted — wire a Data Source upstream so it can do the fetch. | | `symbologies` | array | Restrict decoding to these formats. Empty = any format. | | `max_codes` | number | Cap the number of codes returned per frame (default `8`). | | `try_rotate` | boolean | Search for codes rotated 90°/180°/270° as well as upright (default `true`). | | `try_invert` | boolean | Also attempt light-on-dark / inverted codes (default `true`). | | `try_downscale` | boolean | Also attempt scaled-down versions of the frame (default `true`). | | `binarizer` | string | Threshold strategy: `local_average` (default), `global_histogram`, `fixed_threshold`, `bool_cast`. | ## Outputs | Field | Type | Description | | ------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `codes` | array | One entry per decoded code with `symbology`, `text`, `bytes_b64` (raw payload, for binary Data Matrix), `polygon` (4 pixel corners), `bbox` (`{x1, y1, x2, y2}` in pixels), `orientation`, `ec_level`, `content_type`. | | `count` | number | `len(codes)` after the `max_codes` cap. | | `detections` | array | `call_model`-shaped projection — `class` = symbology, `confidence` = `1.0`, pixel `bbox`. Drop-in for `annotate` / `spatial_filter` / `conditional/detection_event_gate`. | | `source_image_url` | string | Cloud-only. Echo of the resolved upstream `image_url` so `annotate` / `send_alert` can reference the exact frame that was decoded. | | `frame` | image | Edge-only. Pass-through of the input camera frame for a downstream `annotate` overlay. | ## Edge implementation The node compiles into the same `@cw.on_frame` worker that the rest of the perception chain uses. Runtime helpers (`_decode_barcodes`, `_barcode_codes_to_detections`, plus the small `_barcode_position_to_polygon` / `_barcode_polygon_bbox` geometry helpers) are inlined at module scope from `src/lib/workflow_utils.py` via `inspect.getsource()` and shared across multiple `barcode_reader` nodes in the same worker. The `zxing-cpp` wheel is lazy-imported on first decode so missing the optional `barcode` SDK extra surfaces in node logs rather than blocking worker startup. The `edge-ml-worker` Docker image ships with `zxing-cpp` baked in (the `barcode` extra is part of the default `CYBERWAVE_SDK_EXTRAS`). For a custom Pi-slim image, include `barcode` alongside `zenoh` and `schedule` and skip the heavier `ml-*` extras. See [Edge Workers](/feature-reference/workflows/workers/overview) for the full lifecycle. ## Companion nodes * `annotate` — draw decoded barcode boxes on the live overlay channel. * [`spatial_filter`](./spatial-filter) — only count codes that fall inside an author-defined ROI (e.g. the conveyor belt zone). * [`conditional`](./timed-condition) — fire on first-seen, on a new payload, or only after a code has been visible for N frames. * `send_alert` — escalate to an operator with the decoded payload attached. # Prompting Call Model Source: https://docs.cyberwave.com/feature-reference/workflows/call-model-prompt Drive open-vocabulary and multimodal models from the Call Model node by setting a text prompt — works the same on cloud and edge. The `prompt` input on a `call_model` node is the steering knob for any model that accepts free-form text. Set it once in the inspector (or wire it from an upstream node) and the value flows through to the selected model at inference time on every execution path — cloud runner, edge mission worker, and edge `camera_frame` worker. ## Choose a task Choose **Task**, then a compatible model. An unnamed node takes the task name; your own names stay unchanged. The task’s observations appear in **Inputs**, and its typed result appears in **Outputs**. Connect the required image, prompt or other observations before running. Unsupported tasks are unavailable for the workflow's current runtime. **Model default** retains the existing response behavior. Changing a task saves the selection without running the model. If the node or model changed while you were editing, reload before saving again. Edge workflows can call supported cloud models for structured tasks. Update the SDK and republish the workflow after changing the selected model’s configuration. An unsupported runtime or invalid response stops the task; it does not silently switch to an unstructured answer. For mapping, keep the steps explicit: camera image → depth estimation → calibrated point cloud → map. LiDAR provides geometry directly and still needs frame and time alignment. Relative depth is useful for visualization, but cannot replace metric depth in a map. Existing saved prompts remain visible. Editing a legacy prompt moves that value to the current input mapping; other settings remain intact. ## What `prompt` means for each model family | Model family | What the prompt does | | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Open-vocab detectors / segmenters** — YOLOE-26 text/visual, SAM 3 text mode, YOLO-World | Reconfigures the classification head to detect exactly the classes you name. Single class (`"helmet"`), comma-separated for multiple (`"helmet, safety vest"`), or a list when wired from an upstream node (`["helmet", "safety vest"]`). | | **VLMs / LLMs** — Gemini, Gemini Robotics ER, Molmo | The prompt *is* the model input — paired with an image or video for vision tasks. | | **STT / Whisper** | Optional biasing hint that helps the decoder lock onto jargon, proper nouns, or expected phrases. Edge STT catalog models and packages: [Call Model STT on edge](/feature-reference/workflows/call-model-stt-edge). | | **Diffusion / Im2Mesh** | The text-to-image / text-to-3D prompt. | | **Closed-set YOLOv8 / YOLOv11 / classifier nets** | Not consumed. `cyberwave workflow sync` rejects the workflow with a `text_prompt_unsupported` error so you don't silently ship a configuration where the prompt does nothing. | ## Edge open-vocabulary detection For an edge `camera_frame → call_model` chain, the prompt is the cleanest way to add custom classes without retraining: ``` camera_frame → call_model (YOLOE-26 Small, prompt: "helmet") → send_alert ``` The camera worker codegen forwards the resolved prompt into the generated `model.predict(frame, ..., prompt=..., twin_uuid=...)` call. The Ultralytics runtime configures the head once via `set_classes()` and caches that configuration on the model handle, so subsequent frames at 10–30 fps don't pay the re-parameterization cost. If the underlying call fails (bad tokenizer state, OOM during text encoding), the runtime logs a warning and the previously active class set stays live — the worker keeps producing detections rather than crashing, and the warning surfaces the regression. ### Camera-frame limitation: static prompts only Camera workers compile through the legacy `WorkerCodegen` path, which only resolves prompts that are statically known at compile time — `parameters.default_prompt` or `input_mappings.prompt` with `mode: "value"`. Reference-mode mappings that read from an upstream node's output are **accepted by the compatibility gate** (the model takes text, after all) but **dropped by the camera codegen** with a clear warning in the compile output: ``` worker_codegen: call_model has a 'reference'-mode prompt mapping; camera-frame workers can only forward static literal prompts... ``` If you need an upstream-wired prompt for a vision workflow, move the trigger off `camera_frame` so the assembler renders the graph instead — that path threads `_node_outputs` through every node and honors reference / expression mappings end-to-end. ## Single class vs multi-class The inspector's `prompt` field is a single string, so the way to ask for multiple classes is to **comma-separate them**: ```yaml theme={null} prompt: "helmet, safety vest, person" ``` The SDK splits on commas, strips whitespace from each entry, and re-parameterizes the head with the resulting class list. Empty entries (`"helmet, , vest"`) are dropped silently. When the prompt is wired from an upstream node whose output is already a list of strings, that form is accepted as-is — no comma-splitting needed: ```yaml theme={null} prompt: ["helmet", "safety vest", "person"] ``` The runtime returns detections labeled with whichever class fired, and you can filter downstream with `classes: ["helmet"]` or split on the label in a `code` node. ### Prompt-free variants YOLOE checkpoints come in two flavours. Text/visual variants (`yoloe-26*-seg`, `yoloe-26*-det`) re-parameterize the head from your prompt at runtime. **Prompt-free** variants (`yoloe-26*-seg-pf`) bake the vocabulary into the checkpoint at train time — typing a prompt against one would be silently ignored, so the inspector hides the prompt row when a prompt-free variant is selected. ## Attribute binding Open-vocabulary detectors are reliable at *object identity* ("helmet", "ladder", "forklift") and noticeably less reliable at *attribute binding* ("**red** helmet", "**tall** person", "person **with glasses**"). Two patterns help, depending on the workflow shape: **Compound prompt (camera workflows).** Express the attribute as part of a single phrase rather than a comma-separated class list: ```yaml theme={null} prompt: "person wearing glasses" ``` A comma would create two independent classes (`person` OR `glasses`); a single phrase keeps `set_classes` configuring **one** open-vocab class whose text embedding encodes the attribute. Quality depends on how well the phrasing matches what the model saw during training — try a couple of variants ("person with glasses", "person wearing eyeglasses") and tune `confidence_threshold` (often 0.4–0.55 for compound prompts vs. 0.5 default). **Two-stage filter (non-camera workflows).** When you can afford a `code` node — i.e. the workflow is not on a `camera_frame` trigger, which the compiler currently blocks Code nodes on — do: 1. Use `prompt` for the **object** class. 2. Add a downstream `code` node that crops each detection's bounding box and checks the attribute (mean RGB / HSV for color, simple geometry for size). 3. Gate with `detection_event_gate` + `timed_condition` before `send_alert` to debounce. See [`spatial-filter`](./spatial-filter) and [`timed-condition`](./timed-condition) for the surrounding nodes; the prompt change here is purely on the intelligence step. ## When the prompt is rejected at compile time `cyberwave workflow sync` (the backend codegen) fails with a clear message when a `prompt` is configured on a model whose catalog metadata says `can_take_text_as_input = False`. The same rule fires for both edge-activated and cloud-activated workflows — the model either accepts text or it doesn't, regardless of where the inference runs. The inspector mirrors the rule by hiding the prompt row on those models, but the backend is the source of truth: a workflow created through the API or imported from another workspace will be rejected at sync even if it never passed through the editor. To resolve the error, pick an open-vocabulary model (YOLOE-26 text/visual, YOLO-World, SAM 3 text mode), clear the prompt field, or — if the prompt is wired from an upstream node — disconnect that input edge. ## Soft breaking change Before this release, configuring a prompt against a model that couldn't consume text compiled silently and the prompt was dropped on the floor at runtime (closed-set YOLO ignored the kwarg, non-image models never received it). Existing workflows in that state will now fail `workflow sync` with the `text_prompt_unsupported` error. Clear the prompt or switch the model — the new behaviour matches the previous runtime effect, just surfaced at deploy time instead of after a silent detection regression. # Call Model — STT on edge Source: https://docs.cyberwave.com/feature-reference/workflows/call-model-stt-edge Whisper.cpp and Faster Whisper catalog models, dependencies, and compile checks **Call Model** (`call_model`) nodes that select an **edge** or **hybrid** speech-to-text catalog model run inference on-device via `cw.models.load(...).predict(...)`. Cloud-only STT uses `client.mlmodels.run(...)` and does not require edge STT packages. Prompting for STT models is optional biasing — see [Prompting Call Model](/feature-reference/workflows/call-model-prompt). *** ## Catalog models and dependencies Each STT seed sets **one** SDK extra in `metadata.edge_package`. Edge-sync surfaces it in `model_requirements`. | Model | Runtime | Edge extra | Install | | ------------------------------- | ---------------- | --------------- | ---------------------------------------- | | Whisper Tiny EN Q5\_1 | `whisper_cpp` | `ml-stt` | `pip install 'cyberwave[ml-stt]'` | | Whisper Base EN Q5\_1 | `whisper_cpp` | `ml-stt` | same | | Whisper Small EN Q5\_1 | `whisper_cpp` | `ml-stt` | same | | Whisper Tiny Multilingual Q5\_1 | `whisper_cpp` | `ml-stt` | same (+ cloud fallback) | | Whisper Base Multilingual Q5\_1 | `whisper_cpp` | `ml-stt` | same (+ cloud fallback) | | Faster Whisper Tiny EN | `faster_whisper` | `ml-stt-faster` | `pip install 'cyberwave[ml-stt-faster]'` | | Faster Whisper Base EN | `faster_whisper` | `ml-stt-faster` | same | | Faster Whisper Small EN | `faster_whisper` | `ml-stt-faster` | same | Do **not** point catalog metadata at `ml-all`. Pick the extra for the runtime you use. *** ## Weight paths (`edge_model_path`) | Model family | Cache / load path | Notes | | ------------------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | **whisper.cpp** | File path to GGML binary, e.g. `models/whisper/ggml-tiny.en-q5_1.bin` | `download_url` in metadata; first run fetches into edge model cache | | **faster-whisper** | Cache key = `model_external_id` (e.g. `tiny.en`); `metadata.edge_model_path` is documentation only | Edge Core pre-downloads via catalog `model_external_id`; CTranslate2 cache under `/app/models/tiny.en/` | Generated workers emit: ```python theme={null} model = cw.models.load( "tiny.en", runtime="faster_whisper", faster_whisper_model_id="tiny.en", download_root="tiny.en", ... ) ``` *** ## Compile server When a workflow has `run_on_edge: true` and a Call Model node references an on-device STT model, compile verifies imports: | Runtime | Import checked | `base.txt` package | | ---------------- | ----------------------------- | ----------------------- | | `whisper_cpp` | `pywhispercpp.model.Model` | `pywhispercpp==1.4.1` | | `faster_whisper` | `faster_whisper.WhisperModel` | `faster-whisper>=1.1.1` | Failure example: > This workflow uses Call Model with faster-whisper but faster-whisper is not installed on the compile server. Install faster-whisper (or cyberwave\[ml-stt-faster]) on Django before compiling for edge. Rebuild Django after updating `requirements/base.txt` — see [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies). *** ## Edge worker 1. Install the catalog model's extra (`ml-stt` or `ml-stt-faster`). 2. Sync workflow — `edge-sync` lists `model_requirements` with `edge_model_path`. 3. First inference downloads weights (or uses pre-staged files under `~/.cyberwave/models/`). **Audio input:** int16 PCM @ 16 kHz mono (or WAV bytes). The worker passes `sample_rate_hz`, `channels`, and optional `language` / `task` / `vad_filter` (Faster Whisper built-in VAD when enabled). *** ## Choosing whisper.cpp vs Faster Whisper | | whisper.cpp (`ml-stt`) | Faster Whisper (`ml-stt-faster`) | | ---------------- | --------------------------------- | ------------------------------------- | | **Hardware** | Raspberry Pi 4 class | Pi 4+; Jetson/GPU for Base/Small | | **Weights** | Quantized GGML (`.bin`) | CTranslate2 cache dir | | **Latency** | Good for Tiny on CPU | Tiny EN optimized for real-time | | **Built-in VAD** | No (use Audio Assistant upstream) | Yes (`builtin_vad_filter` on catalog) | *** ## Typical wiring ``` audio_track → audio_assistant → wake_word_engine (optional) → call_model (STT catalog model) → fuzzy_matcher ← twin → virtual_controller ``` Wire Call Model **audio** input from upstream `audio` key. Wire **result** (text) into Fuzzy Matcher's **Uncertain String** (`query`). *** ## Related Full matrix (all nodes + compile server) PCM format and pipelines Map STT text to commands # Create Attachment Source: https://docs.cyberwave.com/feature-reference/workflows/create-attachment Upload a new capture (image/file) onto a Twin from a workflow run and tag it with execution metadata. The **Create Attachment** node uploads a new `Attachment` onto a Twin using a URL, `data:` URL, raw bytes, or JSON-serializable payload, then enriches it with the same workflow execution metadata as `update_attachment` so the new attachment shows up under the captures section for the twin/environment and the workflow execution. ## When to use it * A workflow generates a fresh image (annotated frame, model output, screenshot) that you want to persist as a *new* capture rather than overwriting an existing one. * You need an attachment that is discoverable in the environment's **Executions → Gallery** view — the node automatically stamps `metadata.environment_uuid`. * You want the new attachment to appear in the workflow execution's captures list — `metadata.workflow_execution_uuid` is always set. ## Supported file types The node is generic — any file type works: * **Images** — `data:image/png`, `data:image/jpeg`, `data:image/webp`, `image/gif`, `image/heic`, `image/heif`, plus `http(s)://` URLs to image files. * **Video** — `video/mp4`, `video/quicktime` (`.mov`), `video/webm`, `video/x-matroska` (`.mkv`), `video/x-msvideo` (`.avi`). * **Audio** — `audio/mpeg` (`.mp3`), `audio/wav`, `audio/ogg`, `audio/webm`. * **Text / documents** — `text/plain`, `text/csv`, `text/markdown`, `application/json`, `application/pdf`. * **Archives / 3D / binary** — `application/zip`, `model/gltf-binary` (`.glb`), `model/gltf+json` (`.gltf`), `application/octet-stream` (falls back to `.bin`). For `data:;base64,...` URLs the bytes are decoded inline; for `http(s)://...` URLs the bytes are fetched server-side regardless of `Content-Type`. The extension is auto-inferred from the MIME / URL path when the optional `name` input doesn't include one. ## Inputs | Field | Required | Notes | | -------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `twin_uuid` | no | UUID of the twin to attach the file to. Used to derive `environment_uuid` for the captures section. Optional — see anchor rules below. | | `asset_uuid` | no | UUID of the asset to attach the file to (catalog-level artifacts like generated thumbnails or reports about the asset itself). | | `environment_uuid` | no | UUID of the environment for environment-scoped captures (workflow-run artifacts that aren't about a specific twin). Defaults to the workflow's bound environment when neither twin nor asset is supplied. | | `source_url` (label: **Source**) | yes | `http(s)://...` URL, `data:;base64,...` data URL, raw bytes, OpenCV frame, or JSON-serializable `dict` / `list`. Any MIME type. | | `image_bytes` / `frame` | no | Implicit fallbacks — if `source_url` resolves to nothing but raw bytes (`data_source.image_bytes` for `twin_image` / `ip_camera`) or a live camera frame (`camera_frame.frame`) is available, the node uses it directly. No extra wiring needed. | | `name` | no | Optional file name. Extension auto-appended from MIME / URL when missing. Defaults to `workflow_capture_`. | | `capture_type` | no | Stored on `metadata.capture_type`. Defaults to `workflow_capture`. | | `prompt`, `result`, `detections` | no | Capture-time hints saved under `metadata.analysis`. The analysis-enrichment surface (`status` overrides, `error`, `model_name`, `model_uuid`, annotated frames) lives on `update_attachment` so the two nodes have non-overlapping responsibilities. `analysis.status` is always `completed` on create — downstream `update_attachment` overwrites it once async analysis finishes. | | `metadata` | no | Extra dict merged into attachment metadata. Reserved keys (`workflow_*`, `environment_uuid`, `capture_type`, `analysis`) are never overridable. | When `source_url` resolves to a `dict` or `list` (for example `call_model.model_result`, a detections array, or a telemetry row), the node JSON-encodes it (`json.dumps(..., indent=2, default=str)`) and stores it as a `.json` attachment — no explicit serialize step required. ### Anchor rules Every attachment must belong to *something* so it has an ACL parent and a discoverable UI surface. The node accepts any one (or more) of `twin_uuid`, `asset_uuid`, `environment_uuid`. If none of those is supplied, the node falls back to the workflow's bound environment (when set). A workflow that is bound to neither an environment nor any of these three inputs will fail with a clear error rather than silently producing an orphan attachment. Discoverability per anchor: * `twin_uuid` → twin captures + the environment's **Executions → Gallery** view (via auto-stamped `metadata.environment_uuid`) + workflow run captures. * `asset_uuid` → asset attachments + workflow run captures. * `environment_uuid` → the environment's **Executions → Gallery** view + workflow run captures. * workflow-only (workspace anchor via the workflow's workspace) → workflow run captures only. ## Chaining with `update_attachment` `create_attachment.attachment_uuid` is designed to feed straight into `update_attachment.attachment_uuid`. The `analysis` blocks merge — `create_attachment` seeds the initial values (status, prompt, model\_\*) and `update_attachment` overlays additional results (`result`, `detections`, `annotated_image_bytes`) without disturbing top-level keys like `capture_type` or `environment_uuid`. Typical chain: ``` trigger → create_attachment → call_model → update_attachment ↑ ↑ (analyzes the new file) (writes detections, annotated frame back onto the same attachment) ``` ## Outputs * `attachment_uuid` — UUID of the newly created attachment * `metadata` — final attachment metadata after enrichment * `created` — boolean success flag ## Related * [`update_attachment`](/feature-reference/workflows) — enrich an *existing* attachment instead of creating a new one. # Edge workflow dependencies Source: https://docs.cyberwave.com/feature-reference/workflows/edge-dependencies Python packages and SDK extras for voice pipelines — compile server, edge worker, and catalog STT models Edge voice workflows use **three layers** of dependencies. Each layer must be satisfied or compile/sync fails with an actionable error (for example: *"… is not installed on the compile server"*). | Layer | Where | Purpose | | ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------- | | **1. Compile server** | Django / `cyberwave-backend` | Validates imports and (for Wake Word) downloads weights **before** shipping `wf_*.py` | | **2. Edge worker image** | `cyberwaveos/edge-ml-worker` | Runs generated Python; install matching `cyberwave[...]` extras | | **3. Catalog / emitters** | `edge-sync` → `model_requirements` | Tells operators which **one** SDK extra to install per node or STT model | **Do not install `ml-all` on Raspberry Pi** unless you need every vision + STT + VAD runtime in one image. Catalog entries declare **one minimal extra** each (`ml-stt`, `ml-stt-faster`, …). Use `ml-all` only for CI/dev fat images. *** ## Workflow nodes | Node | Compile server (`base.txt`) | Edge SDK extra | `model_requirements` | | -------------------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------- | --------------------------- | | [Audio Track](/feature-reference/workflows/audio-track/overview) | — (no ML import) | `zenoh` on worker; `microphone` on capture host | — | | [Audio Assistant](/feature-reference/workflows/audio-assistant/overview) | `silero-vad` (+ torch transitive) | `ml-audio` | `edge_package: ml-audio` | | [Wake Word Engine](/feature-reference/workflows/wake-word-engine/overview) | `openwakeword`, `onnxruntime` | `ml-wakeword` | `edge_package: ml-wakeword` | | [Call Model — STT](/feature-reference/workflows/call-model-stt-edge) | `pywhispercpp` and/or `faster-whisper` | From catalog metadata | Per selected ML model | | [Fuzzy Matcher](/feature-reference/workflows/fuzzy-matcher) | `rapidfuzz` | `fuzzy-match` | `edge_package: fuzzy-match` | | [Twin](/feature-reference/workflows/twin) | `httpx` (base) | Base `cyberwave` | — | | [Virtual Controller](/feature-reference/workflows/virtual-controller) | `paho-mqtt` (base) | Base `cyberwave` | — | Compile checks mirror the [Wake Word](/feature-reference/workflows/wake-word-engine/models-and-compile) pattern: `WorkflowCodeAssembler` calls `provision_*_for_compile()` before emitting edge worker source. *** ## SDK extras (`cyberwave-python`) Defined in `cyberwave-sdks/cyberwave-python/pyproject.toml`. Install on edge with `pip install 'cyberwave[]'` or `pip install 'cyberwave-edge-core[]'` (thin passthrough). | Extra | Packages | Used by | | --------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ | | `ml-audio` | `silero-vad` | Audio Assistant | | `ml-wakeword` | `openwakeword`, `onnxruntime` | Wake Word Engine | | `ml-stt` | `pywhispercpp` | Call Model — Whisper.cpp catalog models | | `ml-stt-faster` | `faster-whisper` | Call Model — Faster Whisper catalog models | | `fuzzy-match` | `rapidfuzz` | Fuzzy Matcher | | `zenoh` | `eclipse-zenoh` | Audio Track worker hook | | `microphone` | `sounddevice`, `av`, … | Host mic capture (driver side) | | `ml-all` | `ml-all-vision` + `ml-all-audio` (includes `torchaudio`) | **CI/dev only** | | `ml-all-audio` | `openwakeword`, `onnxruntime`, `pywhispercpp`, `faster-whisper`, `silero-vad`, `torchaudio`, `rapidfuzz` | Fat audio image (avoid on Pi) | | `ml-all-vision` | `ultralytics`, `onnxruntime`, `opencv-python`, `tflite-runtime` | Vision-only fat image | *** ## Catalog STT models (`edge_package`) Each public STT catalog entry sets `metadata.edge_package` to **one** extra (never `ml-all`). | Catalog model | `edge_runtime` | `edge_package` | Weight path (`edge_model_path`) | | ------------------------------- | ---------------- | --------------- | ---------------------------------------- | | Whisper Tiny EN Q5\_1 | `whisper_cpp` | `ml-stt` | `models/whisper/ggml-tiny.en-q5_1.bin` | | Whisper Base EN Q5\_1 | `whisper_cpp` | `ml-stt` | `models/whisper/ggml-base.en-q5_1.bin` | | Whisper Small EN Q5\_1 | `whisper_cpp` | `ml-stt` | `models/whisper/ggml-small.en-q5_1.bin` | | Whisper Tiny Multilingual Q5\_1 | `whisper_cpp` | `ml-stt` | `models/whisper/ggml-tiny-q5_1.bin` | | Whisper Base Multilingual Q5\_1 | `whisper_cpp` | `ml-stt` | `models/whisper/ggml-base-q5_1.bin` | | Faster Whisper Tiny EN | `faster_whisper` | `ml-stt-faster` | `models/whisper/faster-whisper-tiny.en` | | Faster Whisper Base EN | `faster_whisper` | `ml-stt-faster` | `models/whisper/faster-whisper-base.en` | | Faster Whisper Small EN | `faster_whisper` | `ml-stt-faster` | `models/whisper/faster-whisper-small.en` | Faster Whisper also sets `faster_whisper_model_id` (`tiny.en`, `base.en`, `small.en`) for CTranslate2. Hybrid models may fall back to the cloud whisper node when not running on edge. See [Call Model STT on edge](/feature-reference/workflows/call-model-stt-edge). *** ## Compile server setup (Django) Packages are listed in `cyberwave-backend/requirements/base.txt`: ```text theme={null} openwakeword>=0.6.0 onnxruntime>=1.16.0 rapidfuzz>=3.0.0 silero-vad>=6.0 pywhispercpp==1.4.1 faster-whisper>=1.1.1 ``` After changing `base.txt`, **rebuild the Django Docker image**: ```bash theme={null} cd cyberwave-backend docker compose -f local.yml build django docker compose -f local.yml up -d django ``` Without rebuild, compile fails with errors like: * *"Wake Word Engine but openwakeword is not installed on the compile server"* * *"Fuzzy Matcher but rapidfuzz is not installed …"* * *"Audio Assistant but silero-vad (or torch) is not installed …"* * *"whisper.cpp but pywhispercpp is not installed …"* * *"faster-whisper is not installed …"* *** ## Edge worker image Default `cyberwaveos/edge-ml-worker` installs a **fat** extra set for dev: `ml,ml-onnx,ml-stt,ml-stt-faster,ml-audio,fuzzy-match,zenoh,image,schedule` plus `openwakeword` via `--no-deps` (Python 3.12). For **Raspberry Pi**, rebuild a slim image with only what your workflow uses: ```bash theme={null} # whisper.cpp Tiny + VAD + wake word + fuzzy (no faster-whisper, no YOLO) docker build \ --build-arg CYBERWAVE_SDK_EXTRAS=ml-stt,ml-audio,fuzzy-match,zenoh,schedule \ -f cyberwave-edge-runtime/runtime-services/workers/edge-ml-worker/Dockerfile . ``` ```bash theme={null} # Faster Whisper STT only docker build \ --build-arg CYBERWAVE_SDK_EXTRAS=ml-stt-faster,ml-audio,zenoh,schedule \ -f cyberwave-edge-runtime/runtime-services/workers/edge-ml-worker/Dockerfile . ``` *** ## Typical voice pipeline (extras needed) ``` audio_track → zenoh (+ microphone on capture host) → audio_assistant → ml-audio → wake_word_engine → ml-wakeword → call_model (STT) → ml-stt OR ml-stt-faster (per catalog model) → fuzzy_matcher → fuzzy-match twin → base cyberwave virtual_controller → base cyberwave ``` Install the **union** of extras used in your graph — not `ml-all`. *** ## Related PCM format and pipeline overview Whisper.cpp vs Faster Whisper on edge Compile-time model download Weight download on device # Execution ingress Source: https://docs.cyberwave.com/feature-reference/workflows/execution-ingress How edges, workers, and SDKs report workflow execution progress back to Cyberwave over MQTT. Workflows that run outside the backend (on edges, in workers, or via the SDK) can report their execution progress back to Cyberwave so that the UI and API expose a live timeline. Ingress is MQTT-only; both the SDK reporter and generated edge workers publish to the topics below, which the backend consumer funnels into the `WorkflowExecution` + `WorkflowNodeExecution` tables. Ingress requires an **environment-bound** workflow. Cloud-owned executions keep using their existing task runner; selecting a model or a Control service does not transfer execution ownership to an edge reporter. ## MQTT topics | Topic | Payload | | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `cyberwave/workflow/{workflow_uuid}/execution/started` | `{ execution_uuid?, trigger_data?, source_type? }` | | `cyberwave/workflow/{workflow_uuid}/execution/{execution_uuid}/node/{node_uuid}` | `{ status, input_data?, output_data?, error_message?, execution_time_ms?, metadata?, source_type?, started_at?, finished_at? }` | | `cyberwave/workflow/{workflow_uuid}/execution/{execution_uuid}/finished` | `{ status, error_message?, source_type? }` | A publisher that reports a node after the fact should send `started_at` / `finished_at` (ISO-8601, or epoch seconds) so the timeline shows when the node ran rather than when the event was received. The backend ignores a reported time that falls outside the execution's own span, so an unsynchronised clock degrades to receipt time instead of placing a node in the future. `reporter.node_started(..., started_at=...)` and `node_finished(..., finished_at=...)` take a `datetime`, epoch seconds, or a formatted string. A reported finish before the recorded start also falls back to receipt time. Generated workers omit these arguments for an older SDK reporter, preserving existing lifecycle events without requiring a coordinated device upgrade. Publishers should set `source_type` to one of `edge`, `sim`, `tele`, or `edit` for lineage. Authentication is broker-level (consistent with other Cyberwave MQTT ingress such as `cyberwave/twin/{uuid}/navigate/status`). Idempotency is enforced on the backend: * Repeat `started` with the same `execution_uuid` returns the existing row without re-seeding node children. * Node events for a node already in a terminal state (`success` / `error` / `skipped`) are ignored — first terminal write wins. * `finished` on an already-terminal execution is a no-op. These guarantees mean at-least-once MQTT delivery is safe: duplicate publishes after reconnects won't corrupt the execution timeline. ## Python SDK `client.workflow_executions.start(...)` returns a `WorkflowExecutionReporter` that owns a single execution and publishes over MQTT. The client must be connected to a Cyberwave-backed MQTT broker — the reporter raises on construction if not. ```python theme={null} client = Cyberwave(api_key="...") reporter = client.workflow_executions.start( workflow_uuid="wf-uuid", source_type="edge", ) try: for node_uuid in node_uuids: reporter.node_started(node_uuid) try: run_node(node_uuid) reporter.node_finished(node_uuid, output_data=[...]) except Exception as exc: reporter.node_error(node_uuid, error=str(exc)) raise reporter.finished(status="success") except Exception as exc: reporter.finished(status="error", error_message=str(exc)) raise ``` A context-manager form (`with client.workflow_executions.start(...) as r:`) marks `success` on clean exit and `error` on exception, so workers don't have to repeat the try/except shape. The initial `started` publish is always strict: if it fails, later node events would reference an execution the backend never saw. Pass `strict=True` to `start(...)` to surface later publish failures as well (the default swallows them after logging, so a transient broker blip doesn't poison a running workflow). ## Generated worker modules Mission workflows compiled with `run_on_edge=true` ship a generated `wf_*.py` that already wires the reporter around every emitted node. Each step in `compiled_payload.steps` carries the emitting node's `node_uuid` so runners that consume the payload directly (cloud-side or custom edge runners) can produce the same events without parsing the generated Python source. The generated worker holds its node events until the end of a tick, so that a frame-driven trigger stays quiet on idle frames, and timestamps each one as it happens — a run's timeline reflects the node durations, not the moment the batch was published. # Fuzzy Matcher node Source: https://docs.cyberwave.com/feature-reference/workflows/fuzzy-matcher Match a noisy/uncertain string against a source of truth (single string or array). Outputs match, score, and match_string. The **Fuzzy Matcher** (`fuzzy_matcher`) takes two inputs — an **uncertain string** (typically STT output) and a **source of truth** (a single string or an array of strings) — and returns the source-of-truth entry that best matches the uncertain input. It uses [RapidFuzz](https://github.com/rapidfuzz/RapidFuzz) composite scoring so imperfect transcriptions still map to the right label. This mirrors the two-input shape of the **Conditional** node, but instead of an exact comparison it returns a similarity score plus the matched string. **Palette category:** Transform & Routing. Runs on **cloud** workflows and **edge** workers (same matching logic in both paths). ## Typical chain ``` audio_track → wake_word_engine → audio_assistant → call_model (STT) → fuzzy_matcher ← twin (control_actuations / control_labels) → virtual_controller / conditional / downstream logic ``` Wire **query** (uncertain string) from Call Model `result`. Wire **candidates** (source of truth) from Twin node **control\_actuations** — either an array, or a single string from any upstream node. Branch on **match** and pass **match\_string** into actuation. ## Inputs | Field | Type | Required | Description | | ----------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | string | Yes\* | **Uncertain string** to match (for example STT output). \*Use a static value in the inspector when unwired. | | `candidates` | string \| array | Yes\* | **Source of truth**: either a single string or an array of strings. A lone string is treated as a one-entry source of truth. \*One label per line in the inspector when unwired. | | `score_threshold` | number | No | Minimum RapidFuzz score (0–100) to set `match` to `true`. Default **80**. Set in the inspector or wire from upstream. | **Inspector (node parameters):** * **Score Threshold** — minimum similarity (0–100) to count as a match. Higher = stricter. Default `80`. * **Uncertain String (optional)** — static fallback when `query` is not wired from upstream. * **Source of Truth (optional)** — one option per line, or a single string. Used when `candidates` is not wired from upstream. Precedence: wired input mapping → node parameter → default (`80` for threshold). ## Outputs | Field | Type | Description | | -------------- | ------- | ------------------------------------------------------------------------------------------------------------------ | | `match` | boolean | `true` when the best source-of-truth entry score ≥ `score_threshold`; `false` otherwise. | | `score` | number | Best RapidFuzz similarity (0–100) for the winning entry, even when `match` is `false`. | | `match_string` | string | The source-of-truth string that best matched the uncertain input (original casing). Empty when `match` is `false`. | **Deprecated aliases** (kept for older workflows): | Field | Alias of | | ----------------- | -------------- | | `matched` | `match` | | `predicted` | `match_string` | | `matched_command` | `match_string` | Advanced echo (debugging): `query`, `candidates`, `score_threshold`. ## How matching works 1. **Normalize** query and each candidate: lowercase, collapse whitespace, treat `_` and `-` as spaces, strip punctuation (`move_forward` → `move forward`). 2. **Score** each candidate with the **max** of: * `token_set_ratio` — extra words, shuffled order * `token_sort_ratio` — similar order with typos * `partial_ratio` (both directions) — label inside a long phrase, or short utterance inside a label * `WRatio` — general typo tolerance 3. Pick the **highest-scoring** source-of-truth entry as `match_string`. 4. Set `match` to `true` only if that score ≥ `score_threshold`. RapidFuzz scores are always on a **0–100** scale (`100` = perfect after normalization). ### Examples (threshold 80) | Query (STT) | Dictionary label | Typical result | | ------------------------------- | --------------------------- | ----------------------------------------------- | | `I want that you move forward` | `Move Forward` | `match: true`, `match_string: "Move Forward"` | | `more forward` / `mole forward` | `Move Forward` | `match: true` (typos) | | `move forwarde` | `move_forward` | `match: true` | | `forward` / `forwarde` | `Move Forward` | `match: true` (substring + typo) | | `what is the time tomorrow` | `turn on the kitchen light` | `match: false`, `match_string: ""`, low `score` | ## Tuning `score_threshold` | Value | Effect | | -------------------- | ------------------------------------------------------------------------------ | | **80** (default) | Balanced for voice commands | | **Lower** (e.g. 70) | More tolerant of noisy STT; more false positives | | **Higher** (e.g. 85) | Stricter; short or typo-heavy utterances may need a higher raw `score` to pass | Use the **score** output to calibrate: if good phrases often score 75–79, lower the threshold slightly; if unrelated text still passes, raise it. ## Execution targets | Target | Notes | | --------- | ---------------------------------------------------------------------------------------------------------- | | **Cloud** | `WorkflowUtils._execute_fuzzy_matcher_node` — requires `rapidfuzz` in backend deps. | | **Edge** | `fuzzy_matcher` code emitter — worker needs `cyberwave[fuzzy-match]` / `cyberwave-edge-core[fuzzy-match]`. | ## Dependencies | Layer | Requirement | | ------------------ | ------------------------------------------------------------------------------------------------------------------------- | | **Compile server** | `rapidfuzz` in `cyberwave-backend/requirements/base.txt`. `provision_fuzzy_match_for_compile()` fails compile if missing. | | **Edge worker** | `cyberwave[fuzzy-match]` or `cyberwave-edge-core[fuzzy-match]` | | **edge-sync** | `model_requirements`: `edge_package: fuzzy-match`, `edge_runtime: rapidfuzz` | Error if compile server lacks the package: > This workflow uses Fuzzy Matcher but rapidfuzz is not installed on the compile server. Install rapidfuzz (or cyberwave\[fuzzy-match]) on Django before compiling for edge. See [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies). ## Related nodes * [Twin](/feature-reference/workflows/twin) — `control_actuations` or `control_labels` → `candidates` * [Call Model STT on edge](/feature-reference/workflows/call-model-stt-edge) — STT `result` → `query` * **Conditional** — branch on `match` * [Virtual Controller](/feature-reference/workflows/virtual-controller) — `match_string` → `command` → MQTT actuation * [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies) — full package matrix # Get Pose node Source: https://docs.cyberwave.com/feature-reference/workflows/get-pose Read a scene object's or twin's live world pose and emit it for downstream nodes. The **Get Pose** (`get_pose`) node reads the current world pose (position + rotation) of a scene object or a twin, fresh each run, and emits it as node outputs. **Palette category:** Data Sources. Generic reader — it emits a raw pose; downstream nodes decide what to do with it. For a **scene object** (procedural primitive), the node returns the **live simulator pose** while a MuJoCo simulation is streaming (so moving the object in sim changes what the node reads), and falls back to the object's authored position when no sim is running. For a **twin** source it returns the twin's stored pose. ## Pose → policy pattern Wire a Get Pose node between a trigger and an [Online Controller Lifecycle](/feature-reference/workflows/online-controller-lifecycle) node: connect Get Pose's **`position`** output to the lifecycle node's **`object_position`** input. On each run the pose is read live and injected as the RL policy's startup goal — move the object and re-run to steer the policy toward its new pose. ## Inputs | Field | Type | Required | Description | | --------------------------- | ------ | -------- | -------------------------------------------------------------------------------- | | `source` | string | No | `procedural_primitive` (default) or `twin`. | | `target_object_external_id` | string | No | External id of the scene object to read (when source is `procedural_primitive`). | | `target_twin_uuid` | string | No | UUID of the twin to read (when source is `twin`). | ## Outputs | Field | Type | Description | | -------------------- | ------ | --------------------------------------------------- | | `position` | array | World position `[x, y, z]`. | | `rotation` | array | World rotation quaternion `[w, x, y, z]`. | | `pose` | object | Combined `{ position, rotation }`. | | `source_external_id` | string | Resolved scene object id (empty for a twin source). | | `source_twin_uuid` | string | Resolved twin uuid (empty for a primitive source). | # Inspect areas with Move Twin Source: https://docs.cyberwave.com/feature-reference/workflows/inspect-area Turn an area into a bounded reach, patrol, or sensor-aware inspection route. Use the existing **Move Twin** node when a robot should reach, patrol, or inspect an area. Cyberwave derives the waypoints for the selected purpose, so you do not need to create a separate area-mission node or manually draw a coverage route. The same node works with drones, quadrupeds, and wheeled robots. Its original **Follow waypoints** purpose remains the default for existing workflows. ## Choose a purpose | Purpose | Result | Sensor required | | -------------------- | -------------------------------------------- | --------------- | | **Follow waypoints** | Follow an authored ordered route | No | | **Reach area** | Navigate to the area's target point | No | | **Patrol perimeter** | Follow the area's boundary | No | | **Inspect area** | Derive a bounded sensor-aware coverage route | Yes | ## Start from a template From **Workflows**, create a workflow and choose a public template. The catalog includes waypoint, reach-area, and inspect-area examples. You can also start with a blank workflow and add **Move Twin** from the node library. Area templates start in **Simulation**, so moving to physical hardware remains an explicit decision. ## Select the area and robot Choose an existing area from the environment, or connect an `area` output from an upstream controller or model node. A connected area is used for that run and does not silently create a permanent environment object. For **Reach area** and **Patrol perimeter**, select a locomotion-capable twin. For **Inspect area**, also choose an imaging sensor available on that twin or on a docked component. If the selected twin cannot perform the requested purpose, the editor explains which capability or calibration is missing instead of presenting the workflow as ready. ## Mark no-go areas Areas and environment objects can carry semantic properties. Use the **Semantics** section in the environment inspector to mark an object as no-go or restricted. You can optionally scope the rule to a particular robot or asset. Structured access tags affect route planning. A free-text semantic description provides context to assistants, but does not weaken or replace a no-go rule. ## Configure inspection coverage For **Inspect area**, select the sensor and set an inspection distance. Cyberwave uses the sensor's declared field of view and range to derive coverage spacing. The preview shows the route, inspection viewpoints, sensor field of view, and covered cells. You can hide sensor overlays from the environment viewer without changing the route. A fixed forward camera usually requires the robot to advance through a deep area. A downward-facing aerial camera can cover the same area from above. A gimballed sensor is accepted only when the deployed runtime can command it and confirm its measured orientation before capture. ## Configure flight transitions For an aerial twin, **Flight transitions** is explicit: | Setting | Behavior | | ------------------------------------ | --------------------------------------------- | | **No transition · already airborne** | Navigate without changing flight phase | | **Take off at start** | Add a takeoff or climb phase before the route | | **Land at end** | Land after the route | | **Take off, then land** | Apply both transitions | The default never infers takeoff or landing from altitude or inspection intent. Simulation also requires an explicit transition when the aircraft starts on a support surface. Live workflows require fresh flight-state telemetry and do not silently arm an aircraft. ## Simulation and Live Use **Simulation** to review the generated route and visual coverage before commissioning. Simulation does not turn an incomplete configuration into a live approval. Before switching to **Live**, confirm that the selected robot advertises the required navigation and inspection actions, the sensor geometry is calibrated, and the environment contains the relevant obstacles and access rules. Dynamic obstacle avoidance, localization, geofencing, emergency stop, and battery limits remain responsibilities of the deployed runtime. Manipulator area inspection is shown as a feasibility requirement until every sensor pose can be checked for reachability, collision, orientation, and capture. Ordinary authored manipulator waypoints remain available for validated arm motion. ## Outputs Move Twin reports the navigation action, selected twin and area, mission purpose, derived waypoint count, coverage summary, and whether per-waypoint capture was requested. Downstream nodes resume after navigation completes and any configured dwell time has elapsed. # Loop node Source: https://docs.cyberwave.com/feature-reference/workflows/loop Repeat a set of steps once per twin or per waypoint, then continue once every item is done. The **Loop** (`loop`) node repeats the steps connected after it, once per item in a list. Use it to run the same work across several robots — or to send one robot to several places — without copying the steps. ## Two branches A Loop has two outputs on the canvas: | Output | When it runs | | ------------------ | -------------------------------------------------------------------- | | **For each item** | Once per item, with that item available to the steps on this branch. | | **After the loop** | Once, after the last item — and only if every item succeeded. | Drag from the branch you want. Steps on **For each item** are the loop body; steps on **After the loop** run once, so that is where a "report that every robot is parked" step belongs. **After the loop** is a success continuation. If any item fails, or the list is empty, that branch is skipped and marked as such in the run history. ## Picking what to repeat over In **Simple** mode, choose a **Type** and then pick the items: * **Twin** — "do this to each of these robots." * **Waypoint** — "send this robot to each of these places." **Advanced** mode hands you the raw `array_data` input, so you can fan out over a list computed by an upstream node. ## Using the item in a step A step inside the loop body takes its value from the iteration rather than from its own picker. Open the step and set its source to **From loop item**: | Node | What binds to the item | | ---------------------------------------------------------------- | -------------------------------------------------- | | Recorder, Data Source, Create Attachment, Send Pose, Move to GPS | The twin it acts on | | Move Twin | The twin it moves, **or** the waypoint it moves to | The control appears on any step inside the loop body, however many steps down the chain it sits. Send Pose keeps its own twin picker when bound. The pose is authored against the twin you pick — its joint names, limits and saved poses — and then sent to each item of the loop. ## Nesting loops A Loop can sit inside another Loop's body: "for each station, for each robot at that station." A step inside the inner loop can take its value from *either* loop — each is offered by name, so you can address the station and the robot in the same step. ## Limits * **Edge workflows** compile one copy of the body per item, so the list has to be a fixed value. With nested loops the copies multiply, and the total is capped — shorten one of the lists if you hit the limit. * A list computed at run time works in the cloud, where the loop iterates as it runs. Set the workflow to run in the cloud for that shape. # Direct GPS targets with Move Twin Source: https://docs.cyberwave.com/feature-reference/workflows/move-to-gps Send a GPS-capable twin to an explicit geodetic target while preserving legacy workflow compatibility. Use **Move Twin** and set **Purpose** to **Use GPS coordinates** to command a GPS-native aircraft—such as a DJI drone—to one explicit geodetic target. This is a direct WGS84 target, not a conversion of an environment waypoint. The older `move_to_gps` node remains executable and editable for saved workflows, but it is hidden from new authoring. Both forms use the same navigation contract in cloud and edge workflows; new integrations should target **Move Twin**. ## Inputs | Field | Meaning | | ------------------------- | ------------------------------------------------------------------ | | `latitude` | WGS84 latitude in decimal degrees, in `[-90, 90]`. | | `longitude` | WGS84 longitude in decimal degrees, in `[-180, 180]`. | | `altitude` | Metres relative to the aircraft takeoff point. | | `heading` | Degrees clockwise from true north, in `[0, 360)`. | | `take_picture_on_arrival` | Capture an image once the twin reaches the target. Off by default. | The node sends the twin to the target and waits for it to report arrival before the workflow continues. The target twin's effective capabilities must explicitly include `geodetic` in `navigation_coordinate_frames` and declare a positive `max_altitude`. Its deployed instance must advertise the matching navigation command and geodetic frame when the asset requires a runtime probe. Coordinates are absolute GPS positions — they are not relative to your environment's origin, and altitude is measured from the aircraft's takeoff point rather than from the environment floor. A direct GPS target never authorizes takeoff or landing. The standard policy assumes the aircraft is already airborne with fresh GPS and flight-state telemetry; flight-phase changes remain explicit. GPS rover support needs a distinct vertical reference contract and is intentionally not inferred from this aircraft mode. Direct GPS is currently live-only: simulation activation is blocked until the environment geo reference can materialize geodetic targets as simulator-native Cartesian positions. ## Outputs `action_id`, `navigation_response`, and the terminal `navigation_result`. `navigation_result` is the platform's record of the completed action: `status` and `message` at the top level, with progress details such as `reached_waypoint_count` under `metadata`. When `take_picture_on_arrival` is on, the node also outputs the captured image: `file_url` (and its `image_url` alias, so a downstream **Call Model** node receives it over a plain connection), `attachment_uuid`, `capture_count`, and `captures`. # MQTT trigger and Send MQTT Source: https://docs.cyberwave.com/feature-reference/workflows/mqtt-trigger How workflow nodes subscribe to and publish MQTT topics on edges and in the cloud. Workflows can react to twin-scoped MQTT messages with the `mqtt` trigger and publish twin-scoped messages with the `send_mqtt` action. The behaviour mirrors the alert trigger pattern (`@cw.on_alert(twin)` edge-side, `_dispatch_cloud_alert_workflows` cloud-side). ## Edge execution The workflow code assembler emits a `@cw.on_mqtt(twin_uuid, subtopic=..., qos=...)` decorated handler: ```python theme={null} @cw.on_mqtt("11111111-...", subtopic="status", qos=1) def run(payload, topic, ctx, client=None): ... ``` The Cyberwave SDK runtime owns the broker subscription via `client.mqtt.subscribe(...)`, so the worker module stays declarative (no per-trigger blocking loop). Multi-trigger workflows can mix MQTT triggers with camera-frame and audio-track triggers because the emitter opts into the per-trigger function path. Each handler runs on its own thread, so a slow handler no longer holds up other triggers or the worker's own broker traffic. Messages for a single handler stay in order and are processed one at a time; if a handler falls far enough behind, further messages for it are dropped rather than queued without bound. ## Cloud execution When the workflow is **not** flagged as `run_on_edge`, dispatch is handled cloud-side by `src.app.services.mqtt_workflow_dispatch.dispatch_cloud_mqtt_workflows`. The backend's existing `@mqtt_subscribe` handlers call the dispatcher after running their primary side-effect, so cloud workflow triggers fire **without adding new broker subscriptions**. Wired subtopics (low-frequency / state-change channels): * `event` — generic twin event stream * `telemetry` — lifecycle (`connected`, `disconnected`, `telemetry_start`, `telemetry_end`, `initial_observation`, …) * `metrics` — battery, navigation status, AMR analytics * `scale` — twin scale updates * `map_update` — point-cloud / occupancy-grid snapshots * `navigate/status` — navigation action status transitions Deliberately not wired (high-frequency, footgun for per-message workflow dispatch): `edge_health` (\~5 s per twin), `depth` (per frame). Edge workers continue to subscribe to those topics directly via `@cw.on_mqtt`. User-defined subtopics outside the consumer's subscription list at all (`command`, `position`, `joint_states`, `alert`, custom names …) work end-to-end on edge only. See `cyberwave-backend/README.md` for the full coverage matrix. The dispatcher keeps per-message overhead bounded with a 60 s Redis-backed cache of the active `(twin_uuid, subtopic)` trigger keys; messages with no matching trigger short-circuit on the cache lookup. ## Send MQTT `send_mqtt` is edge-only by design. Cloud workflows publish via the backend's `send_update_to_mqtt` celery task instead. The emitter: * Validates literal `payload` parameters as JSON objects at compile time. * Wraps non-dict runtime payloads under `{"value": }` so the broker message stays well-formed. * Wraps `client.mqtt.publish(...)` in `try/except` so the per-node `sent` flag accurately reflects whether the publish succeeded. ## Schemas Trigger parameters: `{ twin_uuid, subtopic, qos? }`. Send-MQTT parameters: `{ twin_uuid, subtopic, payload, qos? }`. `subtopic` is the segment after `cyberwave/twin/{twin_uuid}/` — relative, no leading slash, no `+`/`#` wildcards. # Object Pose node Source: https://docs.cyberwave.com/feature-reference/workflows/object-pose Lift a 2D detection into a camera-frame 3D pose using a registered depth map. `object_pose` is an edge perception node that takes a bounding-box detection from any upstream detector — `call_model`, `barcode_reader`, or any node that emits a `detections` array — plus a color-registered depth map, and returns a metric 3D position in the camera's optical frame. A companion ROS 2 node (`cyberwave_object_pose_transform`) can tf2-lift that pose into `base_link` or any other frame configured in your robot's URDF; the workflow node itself stays out of TF resolution so it runs unchanged across robots. Alternatively, set `target_frame` on the node itself (see Inputs below) to re-express `position` directly in the output, with no ROS 2 hop — this requires the twin's driver to publish a live transform snapshot the node can read. Typical chain for a "detect and locate" perception workflow: ``` trigger (camera_frame) → data_source (twin_depth) → call_model (YOLO / VLM) → object_pose → send_controller_command / conditional / send_alert ``` ## Inputs | Field | Type | Required | Description | | -------------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sensor_id` | string | ✓ | ID of the camera sensor in the twin's sensor list. The sensor must declare `width`, `height`, and a field of view (`fov_degrees` or `fovy`). | | `detections` | array | ✓ | Detection list from an upstream node. Auto-wired when placed downstream of `call_model` or `barcode_reader`. | | `depth_mm` | object | ✓ | Color-registered depth map in millimetres. Auto-wired when placed downstream of a `data_source` node with `data_type = twin_depth`. | | `orientation` | object | | Optional upstream quaternion `{x, y, z, w}`. Falls back to identity when not connected. | | `target_class` | string | | Only accept detections matching this class label. Empty (default) = highest-confidence detection regardless of class. | | `min_detection_confidence` | number | | Minimum detector confidence (0–1) to accept a detection. Default `0.3`. Advanced. | | `min_depth_fill` | number | | Minimum fraction (0–1) of pixels in the patch around the bbox centre that must carry valid depth. Default `0.3`. Advanced. | | `patch_radius` | number | | Half-side of the depth-sample patch in pixels. Larger values tolerate more holes but may bias toward background. Default `3`. Advanced. | | `detection_frame_width` | number | | Width of the frame the detector ran on, when different from the sensor resolution. `0` = same as sensor. Advanced. | | `detection_frame_height` | number | | Height equivalent of `detection_frame_width`. Advanced. | | `target_frame` | string | | Optional frame to re-express `position` in (e.g. `base_link`). Requires the twin's driver to publish a live transform snapshot for the same `sensor_id`. Empty (default) keeps `position` in the camera's optical frame. Advanced. | | `target_frame_max_age_ms` | number | | Maximum age of the cached transform before it's treated as unavailable. Only applies when `target_frame` is set. Default `250`. Advanced. | ## Outputs | Field | Type | Description | | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `position` | object | `{x, y, z}` in metres, in the frame named by `frame`. `null` when `depth_valid` is false, or when `target_frame` is set but no transform snapshot was available. | | `frame` | string | Frame `position` is expressed in: `camera` (default) or `target_frame`'s value once a snapshot was available. | | `orientation` | object | Quaternion `{x, y, z, w}` — pass-through from the orientation input, or identity. | | `score` | number | Confidence of the source detection. | | `depth_fill` | number | Fraction of patch pixels that had valid depth (0–1). | | `depth_valid` | boolean | `true` when depth filled the patch above the threshold. `position` is only populated when this is `true`. | | `bearing` | object | Depth-independent unit direction `{x, y, z}` in the camera frame. Always populated — useful for lateral steering when depth is missing. | | `pixel` | object | Bbox centre `{u, v}` in depth-image pixels (after resolution rescaling). | ## Camera calibration Intrinsics (`fx`, `fy`) are derived at workflow compile time from the sensor's declared field of view. The principal point (`cx`, `cy`) defaults to the image centre when no calibration data is present. For cameras with a factory-calibrated principal point — such as the Intel RealSense D455, whose `cx`/`cy` can be \~10 px off-centre at 640×480 — add the calibrated values to the sensor's `parameters` in the asset schema. Without them, lateral pose error can reach several centimetres. ```yaml theme={null} sensors: - id: color_camera type: rgb parameters: width: 640 height: 480 fovy: 55.0 cx: 310.5 # from factory data sheet or ros2 run camera_calibration cy: 235.8 ``` `cx` and `cy` are optional. Omitting them falls back to image centre, which is fine for cameras with low distortion or when sub-centimetre accuracy is not required. ## Companion nodes * `data_source` (with `data_type = twin_depth`) — supplies the registered depth map. * `call_model` — upstream YOLO / VLM detector that produces the `detections` array. * [`barcode_reader`](./barcode-reader) — alternative upstream detector for code-scan use cases. * `spatial_filter` — filter the resulting pose by a 3D region of interest. * `send_controller_command` — send a robot command based on the located object. # Online Controller Lifecycle node Source: https://docs.cyberwave.com/feature-reference/workflows/online-controller-lifecycle Start or stop a twin's assigned online controller, optionally steering an RL policy toward a scene object's current pose. The **Online Controller Lifecycle** (`online_controller_lifecycle`) node starts or stops the online controller assigned to a twin. On a manual (or any) trigger it deploys the twin's primary controller policy, optionally auto-stopping after a set duration. **Palette category:** Actuation. Uses the twin's **assigned** controller policy — assign one on the twin first. ## Steer an RL policy toward an object pose For RL-task policies you can have the node **collect a target object's pose at trigger time** and pass it to the policy as its startup goal (inference command). This is the "pose → policy" pattern: run the workflow and the policy is steered toward the target. Point the node at the object whose pose is the goal: * `target_object_external_id` — a scene object (e.g. a procedural primitive) in the workflow's environment, or * `target_twin_uuid` — a twin whose world pose is the goal. The node reads that entity's **authored** pose each run (the scene object's authored primitive position, or the twin's stored world pose) and starts the policy with an `object_position` inference command. This requires the policy's RL task to declare an `object_position` inference command; set `command_name` when the task declares more than one. When resolved inside this node, the `target_*` params use the **authored** pose, not the live simulator pose. To seed the policy with a target's **live** sim pose, use a [Get Pose](/feature-reference/workflows/get-pose) node upstream (it prefers the live streamed pose) and wire its `position` output into `object_position`. ### Or wire the pose from a Get Pose node Instead of resolving the pose inside this node, you can keep the pose-reading step as a separate, visible node: put a [Get Pose](/feature-reference/workflows/get-pose) node between the trigger and this node, and wire its `position` output into this node's **`object_position`** input. The mapped pose takes precedence over the `target_*` params. ## Live vs. simulation starts The node does **not** take a mode input — it follows the **workflow's execution target** (the Live/Simulation toggle on the workflow), the same convention the recorder and navigation nodes use. When the workflow runs **live**, the controller drives the physical robot on the twin's bound edge; a live start against a twin whose edge is online requires `confirm_live` to be `true`, otherwise the safety gate rejects it. For live RL-task dispatches you can also pick the controller↔plant `transport` (`mqtt` default, or `zenoh` for the low-latency edge DataBus when the driver declares it); simulation runs ignore transport and `confirm_live`. ## Inputs | Field | Type | Required | Description | | --------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `twin_uuid` | string | Yes | Twin whose assigned controller is started/stopped. | | `action` | string | Yes | `start` or `stop`. | | `duration_seconds` | number | No | Auto-stop after N seconds (0 = run until stopped). | | `runtime_params` | object | No | Parameters passed to the controller at startup. | | `device` | string | No | Inference device override (`cpu`/`gpu`). | | `transport` | string | No | Live dispatch wire transport: `mqtt` (default) or `zenoh` (edge low-latency DataBus). Ignored in simulation. Mode itself is inferred from the workflow execution target. | | `confirm_live` | boolean | No | Acknowledge this may drive a real robot. Required to start when the twin's edge is online; otherwise the start is rejected. | | `object_position` | array | No | RL policies: explicit `[x, y, z]` goal (e.g. wired from a Get Pose node's `position`). Takes precedence over `target_*`. | | `inference_command` | object | No | RL policies: a fully-formed startup inference command payload, used verbatim. Highest precedence. | | `target_object_external_id` | string | No | RL policies: scene object whose authored pose seeds the inference command. Mutually exclusive with `target_twin_uuid`. | | `target_twin_uuid` | string | No | RL policies: twin (in the workflow's environment) whose stored world pose seeds the inference command. | | `command_name` | string | No | RL policies: inference command term to seed (defaults to the task's single command). | # Recorder node Source: https://docs.cyberwave.com/feature-reference/workflows/recorder Start or stop audio/video recording on a twin via the media service from a workflow. The **Recorder** (`recorder`) node publishes `start_recording` / `stop_recording` to a twin's `webrtc-command` MQTT topic so the media service persists the **already-running** WebRTC stream to its configured bucket. The node never carries the media itself — the camera or microphone must already be streaming. **Palette category:** Actuation. **Edge-only.** Toggles persistence on the media service; it does not create the stream. The Recorder node, the audio widget's **REC** button in the environment view, and the [microphone driver's fallback relay](/feature-reference/edge/drivers/native-microphone-driver) all publish the exact same payload on `cyberwave/twin/{uuid}/webrtc-command`. The three paths converge on the same media-service handler and the same `webrtc-command/status` ACK, so you can mix and match without changing the consumer. ## Inputs | Field | Type | Required | Description | | -------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `twin_uuid` | string | Yes | Twin whose stream should be recorded. Defaults to the workflow's bound twin. | | `command` | string | Yes | `start_recording` or `stop_recording`. Wire from an upstream Conditional / Fuzzy Matcher to toggle dynamically, or pin a literal in the inspector. | | `frontend_type` | string | Yes | `video` or `audio`. The media service treats this as `audio` when unset. | | `sensor` | string | Yes | Sensor identifier (e.g. `camera`, `mic`). Required by the media-service `start_recording` handler — commands without it are refused. | | `stream_source` | string | No | Optional producer hint (e.g. `camera`). | | `stream_instance_id` | string | No | Optional disambiguator when a twin publishes multiple streams under the same sensor. | ## MQTT payload Published to `{prefix}cyberwave/twin/{twin_uuid}/webrtc-command` with QoS 1: ```json theme={null} { "command": "start_recording", "source_type": "edge", "sensor": "camera", "frontend_type": "video", "stream_source": "camera", "stream_instance_id": "primary" } ``` To stop, send the same payload with `"command": "stop_recording"`. Status is published back by the media service on `{prefix}cyberwave/twin/{twin_uuid}/webrtc-command/status`. ## Outputs | Field | Type | Description | | --------- | ------- | --------------------------------------------- | | `command` | string | Recording command that was published. | | `topic` | string | Full MQTT topic the command was published to. | | `payload` | object | Payload sent to the media service. | | `sent` | boolean | Whether the broker accepted the publish. | ## Execution targets | Target | Behavior | | --------- | --------------------------------------------------------------------------------------------------------------- | | **Edge** | Emitter renders a `client.mqtt.publish` against the twin-scoped `webrtc-command` topic in the generated worker. | | **Cloud** | Not supported — the node raises at compile time for cloud workflows. | ## Related * [Audio in workflows](/feature-reference/workflows/audio-in-workflows) * [Virtual Controller](/feature-reference/workflows/virtual-controller) — generic controller actuation publisher * [Send MQTT](/feature-reference/workflows/edge-dependencies) — generic edge-side MQTT publish # Reusing chains across upstreams Source: https://docs.cyberwave.com/feature-reference/workflows/reusing-chains Fire a shared downstream chain once per inbound activation, with each firing reading its inputs from the upstream that triggered it. The Level 1 workflow activation primitives let you share a downstream chain across many upstream nodes without duplicating the chain per branch. They apply to **every node type** — not just `call_model` — so the same pattern works whether the head of the shared chain is a `call_model`, a `conditional`, a `send_alert`, a custom `code` node, or anything else. ## The primitive: `caller` input-mapping mode Resolves a field from the **immediate predecessor on the current execution path** (the "caller"), instead of a fixed upstream UUID. ```jsonc theme={null} { "input_mappings": { "image_url": { "mode": "caller", "field": "image_url", "source_port": "main", "default": null } } } ``` Available on any input field of any node type. When the engine executes the node, it reads `image_url` from whichever upstream just fired on this branch. ## Fan-in semantics are derived Caller-mode mappings change the node's fan-in semantics implicitly — there is no separate user-settable `fan_in_mode` field. The runtime resolver derives the mode from the graph: * **Caller-mode mapping on the node** → fires **once per inbound activation** (`"any"`). Each upstream firing produces an independent execution row. * **Single direct upstream that resolves to `"any"`** → inherits `"any"` to avoid the silent-coalescing trap where a downstream node would otherwise dedupe N upstream activations to one firing. * **Otherwise** → `"all"`: the node waits for every upstream to complete and then fires once (synchronization barrier). Multi-upstream barrier nodes are intentionally **not** covered by the inheritance rule — they are real convergence points and propagating `"any"` to them would silently break valid use cases. ## Example: shared call-model branch in a patrol workflow ``` trigger → move_twin_1 ┐ trigger → move_twin_2 ├→ call_model (caller-mode: image_url) trigger → move_twin_3 ┤ trigger → move_twin_4 ┘ → conditional → send_alert ``` Each of the four `move_twin` nodes produces its own image URL. The shared `call_model` head declares a `caller`-mode mapping for `image_url`, which both selects the per-activation field source and implicitly makes the head a fan-in `"any"` node. The same downstream `conditional` and `send_alert` chain runs once per `move_twin` firing, with each run reading its image from the correct upstream. ## Example: `conditional` as the activation head The primitive is not specific to `call_model`. The same shape works when the shared head is a `conditional`, a `send_alert`, a custom `code` node, etc. The diagram is identical — only the node type changes — and the runtime semantics are the same. ## Where the primitive runs * **Cloud interpreter** (`run_on_edge=false`): supports caller-mode mappings natively today. * **Edge codegen** (`run_on_edge=true`): supports `caller`-mode mappings on linear chains. Multi-trigger workflows that include a caller-mode (any-derived) node are **rejected at compile time** with a clear error pointing at the offending node; full activation-helper lowering is the subject of a follow-up. The cloud interpreter handles the same workflow today. ## Recording Each `WorkflowNodeExecution` row records `caller_uuid` and `activation_index` under `metadata`, so timeline replay can group runs by `(node_uuid, activation_index)` and reproduce the per-activation flow deterministically. # Send Controller Command node Source: https://docs.cyberwave.com/feature-reference/workflows/send-controller-command Send a specific controller command to a twin with explicit controller and command selection. The **Send Controller Command** (`send_controller_command`) node provides a direct way to dispatch controller commands to a digital twin. Unlike Virtual Controller (which resolves commands dynamically from upstream strings), this node lets you **explicitly select** the twin, controller policy, and specific command at configuration time. **Palette category:** Actuation. Runs on **cloud** (Celery MQTT or inference dispatch) and **edge** (worker `client.mqtt.publish`, keyboard/teleop only). Model controllers (mlmodel/vla) are cloud-only. ## Configuration flow The inspector guides you through a three-step cascade: 1. **Select digital twin** — choose the target twin in the bound environment 2. **Select controller policy** — pick from compatible controllers (filtered by the twin's asset) 3. **Select command** (keyboard/teleop) or **configure instruction** (model controllers) For keyboard/teleop controllers the command dropdown lists every available actuation from the policy's `keyboard_bindings` and `display_config.widgets`. For model controllers the **instruction** input accepts a text prompt for inference. ## Inputs | Field | Type | Required | Description | | ------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------------------- | | `twin_uuid` | string | Yes | Target twin. Set in inspector (Twin combobox). | | `controller_policy_uuid` | string | Yes | Controller policy. Set in inspector (Controller dropdown). | | `command` | string | No | Actuation string for keyboard/teleop controllers (e.g. `move_forward`). Set in inspector or wired from upstream. | | `params` | object | No | Command parameters (e.g. `{"linear_x": 1.5}`). Overrides binding defaults. Can be wired from upstream. | | `instruction` | string | No | Text prompt for model/VLA controllers. Ignored for keyboard controllers. | ## Keyboard/teleop controllers When a keyboard or teleop controller is selected: * The command dropdown shows all available actuations with labels and key bindings * The `params` input can override the binding's default `playground` data (velocity, etc.) * At runtime the node publishes to `cyberwave/twin/{uuid}/command` with the same MQTT payload shape as keyboard teleoperation ### MQTT payload ```json theme={null} { "source_type": "tele", "command": "move_forward", "data": {"linear_x": 1.5}, "timestamp": 1710000000.0 } ``` | Field | Cloud workflow | Edge worker | | ------------- | ---------------------------------------- | ------------------------- | | `source_type` | `tele` (live) or `sim_tele` (simulation) | `edge` | | `command` | Selected actuation slug | Selected actuation slug | | `data` | From `params` input or binding defaults | From `params` input | | `timestamp` | Server-side `time.time()` | Worker-side `time.time()` | ## Model controllers (mlmodel/vla) When a model controller is selected: * The instruction input accepts a natural language prompt (e.g. "pick up the red block") * Additional parameters (max\_steps, mode) can be passed via `params` * At runtime the node dispatches inference through `ControllerPolicyExecutionService` * Model controllers run **cloud-only** — edge compilation will fail ## Outputs | Field | Type | Description | | ------------------------ | ------- | ------------------------------------- | | `twin_uuid` | string | Target twin | | `controller_policy_uuid` | string | Controller policy used | | `controller_type` | string | e.g. `teleop`, `mlmodel`, `vla` | | `command` | string | Actuation or instruction sent | | `sent` | boolean | Whether the command was dispatched | | `topic` | string | MQTT topic (keyboard/teleop) | | `payload` | object | Full MQTT payload or inference result | | `source_type` | string | `tele` / `sim_tele` / `edge` | ## When to use | Scenario | Recommended node | | -------------------------------------------------------------------- | ----------------------------------------------- | | Send a **specific known command** (e.g. "move forward at speed 1.5") | **Send Controller Command** | | Resolve a **dynamic command** from voice/text input | **Virtual Controller** + Fuzzy Matcher pipeline | | Send a **raw MQTT message** with custom topic and payload | **Send MQTT** | ## Related nodes * **Virtual Controller** — dynamic command resolution from upstream strings * **Info Controller** — read controller policy metadata * **Send MQTT** — generic MQTT publish # Send Depth node Source: https://docs.cyberwave.com/feature-reference/workflows/send-depth Display depth estimates from a model on a twin. **Send Depth** displays an upstream model's depth estimates on a twin in an edge workflow. In **Call Model**, choose **Depth estimation**, select an available model, and connect its camera image input. ## Typical chain ``` trigger (camera_frame) → call_model (depth-estimation model) → send_depth ``` Pipe the same `call_model` output into `object_pose` when the model is metric to lift 2D detections into 3D positions. Relative depth is useful for visualization but does not measure distance. A displayed point cloud does not establish calibration, localization or a map. ## Inputs | Field | Type | Required | Description | | ----------- | ------ | -------- | -------------------------------------------------------------------------------------------- | | `depth_map` | array | ✓ | H×W float32 depth map. Auto-wired when placed downstream of a depth-estimation `call_model`. | | `twin_uuid` | string | ✓ | Twin on which to display the depth. | ## Parameters | Field | Default | Description | | ------------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `output_mode` | `normalized_uint16` | Normalized encodes a display range. Metric millimetres uses the model's actual distance scale; choosing it does not make a relative model metric. | | `scale_factor` | `1000.0` | Applied only in `metric_mm` mode. Metres → millimetres by default. | | `publish_every_n_frames` | `1` | Throttle. Set higher on tight uplinks. | ## Notes * Edge-only. The node is filtered out of cloud workflows at compile time. * Relative or unknown depth can remain visible, but cannot be used for metric depth recording or fusion. Use a metric model with confirmed output units for those steps, then configure camera calibration and the required spatial frames. # Send Pose node Source: https://docs.cyberwave.com/feature-reference/workflows/send-pose Move a twin into a saved or custom joint pose by publishing a joint command. The **Send Pose** (`send_joint_commands`) node commands a robot into a **joint pose** — a set of per-joint target angles. When the node runs it publishes a multi-joint message to the twin's joint topic; the driver moves the robot to those positions. **Palette category:** Actuation. Runs on **both** cloud and edge — in the cloud workflow runner, and compiled into the edge worker when the workflow is edge-targeted (so it still works with no cloud connection). It works in **both live and simulation**: when the workflow runs in simulation the pose moves the twin in the simulator; in live mode it drives the physical robot. ## Requirements The twin must expose independently commandable joints and have a runtime that accepts joint commands. Selecting a target preserves its existing control configuration; it does not assign a controller policy. Live execution checks edge health before publishing. Publishing a command does not prove that the robot reached its target. ## Configuration flow 1. **Target Twin** — pick the twin to control. Joint data from another robot does not change this selection. Only **joint-controllable** twins (robots with movable joints) appear in the list. **Required.** 2. Choose a command source: **Twin Poses** for a saved/custom pose, or **Connected joint values** to map positions, velocities or efforts from another workflow node. Use **Clear pose** to use connected values alone. A target and at least one enabled command source are required. A manual trigger alone does not supply joint values. Connected values override matching joints in a selected pose; they can also be used without a pose. Runtime validation rejects an empty command after filtering invalid values and unsupported joints. 3. **Advanced** (optional) — under **Control Settings**, choose which channels to send with the **Positions / Velocities / Efforts** checkboxes (and set per-joint velocity/effort values); under **Explicit Joint Update**, restrict the message to specific joints. The **Message Preview** shows the configured static values. Connected values are resolved when the workflow runs. ## Poses Poses are named joint snapshots stored on the twin/asset. The dropdown lists each pose with its joint values, plus a **Custom Pose** option: * The custom editor shows only the twin's **movable joints** with a numeric field each (keyboard-editable). * Values are validated against each joint's real limits — out-of-range values turn red and block saving. * Give the pose a name and save; it's stored on the twin and can be reused (and edited later) from the dropdown. ## Velocities & efforts By default a Send Pose message carries just the pose's **positions**. Velocities and efforts are included automatically **only when the pose/inputs already provide those values**; otherwise you enable them explicitly under **Advanced → Control Settings** (**Velocities** / **Efforts**). When a channel is enabled, set per-joint values (validated against the joint's limits); any joint you leave unset is **omitted** from the channel ("not commanded"), **not** sent as `0`. This keeps "no velocity/effort command" distinct from an explicit command of zero. Turning a channel off (or leaving it off) omits it from the message entirely. ## Explicit (partial) joint update By default the node sends a **full joint update** — every joint of the pose is included. Under **Advanced → Explicit Joint Update**, flip the switch to send only specific joints: a checklist of the twin's movable joints appears, and only the ones you check are included in the message (across every enabled channel). Use this to command a subset of joints while leaving the rest untouched. ## Inputs | Field | Type | Required | Description | | ------------------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------- | | `twin_uuid` | string | Yes | Target twin (inspector picker, joint-controllable only). | | `pose_name` | string | No | Saved/custom pose, as an alternative to joint values. | | `positions` | object | No | Per-joint target positions (radians/metres). Set by the pose/custom editor or wired from upstream. | | `velocities` | object | No | Per-joint target velocities. Sent only when **Send velocities** is enabled; unset joints are omitted, not `0`. | | `efforts` | object | No | Per-joint target efforts. Sent only when **Send efforts** is enabled; unset joints are omitted, not `0`. | | `include_positions` | boolean | No | Send the positions channel. Defaults on. | | `include_velocities` | boolean | No | Send the velocities channel. Unset = auto (on only when velocity values are present); set to override. | | `include_efforts` | boolean | No | Send the efforts channel. Unset = auto (on only when effort values are present); set to override. | | `explicit_joints_enabled` | boolean | No | Send only the joints in `explicit_joints` (partial update). Default `false` = full joint update. | | `explicit_joints` | array | No | Joint names to include when explicit update is on; all others are omitted. | ## Outputs | Field | Type | Description | | -------------------------------------- | ------- | ---------------------------------- | | `twin_uuid` | string | Twin that received the command. | | `positions` / `velocities` / `efforts` | object | The commanded values. | | `pose_name` | string | The pose that was sent, if any. | | `sent` | boolean | Whether the publish was attempted. | | `topic` | string | The joint topic published to. | ## Example ``` [Trigger: Manual] → [Send Pose: "home"] → [Wait] → [Send Pose: "pick"] ``` Chain multiple Send Pose nodes to move a robot through a sequence of poses. On edge the whole sequence runs locally with no cloud round-trips. ## Related nodes * **Send Controller Command** — issue a controller-policy command (e.g. a drive burst). * **Virtual Controller** — resolve a command dynamically from upstream input. * **Get Pose** — read a twin's current pose. # Running a workflow in simulation Source: https://docs.cyberwave.com/feature-reference/workflows/simulation-execution-target Set a workflow's execution target to Simulation to run it against a cloud physics simulation instead of real hardware Every workflow has an execution target: | Target | Where twin commands go | | ------------------ | ---------------------------------------------- | | **Live** (default) | Real hardware, through your edge drivers. | | **Simulation** | A cloud physics simulation of the environment. | Set it from the workflow's runtime badge in the environment's workflow list. ## Simulation runs are provisioned for you Triggering a Simulation workflow starts a simulation for its environment if one is not already running, and waits for the physics to be ready before the first twin command is sent. An already-running simulation is reused rather than restarted, so you can watch the run live. You need write access to the environment to trigger a Simulation workflow. A Simulation run needs simulation capacity in your workspace. If none is available the run fails with the reason instead of hanging. ## Edge workflows can run against the simulation Perception nodes and pose models only run on an edge, so a workflow using them needed a robot before it could run at all. It no longer does: a simulation can host the workflow itself, reading the simulated cameras. This needs **both** settings, and there is no default for the second: 1. Turn on **Run on edge** for the workflow. 2. Set its execution target to **Simulation**. Then start the environment's simulation. The workflow runs against the simulated camera and depth streams exactly as it would beside a real camera — the same graph, unchanged, on either. Activate the workflow **before** starting the simulation. A simulation that started with no Edge + Simulation workflow in its environment is not hosting a workflow, and activating one afterwards will not reach it — stop the simulation and start it again. Once a simulation is hosting one, activating a further workflow takes effect within about 15 seconds, and deactivating one within about half a minute. A workflow left on the **Live** target is untouched by this: it stays on your real hardware and is never duplicated into the simulation. ## Robot arms follow waypoints through IK A **Move Twin** node pointed at a fixed-base arm treats each waypoint as a target for the arm's end effector, solving the joint angles that reach it. The arm's catalog entry must declare an end-effector frame; arms without one, and other jointed-but-anchored objects such as pan-tilt mounts, keep the base navigation behaviour. Waypoints may be placed in the environment or relative to the arm's own base link — those are the two frames an arm accepts, on either target. Each waypoint's authored duration becomes the time the arm takes to move to it. This solving happens in the cloud, for the simulation only. On a **Live** target the same node sends the waypoints to the robot and its own driver plans the motion — so the arm moves in a straight line and refuses a path it cannot reach without a collision. A Live arm therefore needs a driver that supports waypoint missions (MoveIt on our ROS 2 drivers). If the arm's driver does not, the run fails immediately saying so rather than waiting on a robot that will never move — switch the target to **Simulation**, or bind a driver that does. Today, the Kinova Gen 3 is the only arm whose driver plans waypoint missions. Joint-streaming arms, including the SO-101 and UR7, support Move Twin on the **Simulation** target only. A catalog that explicitly contains the `navigate/command` topic remains valid even if it is maintained manually. Only a current catalog that omits the topic refuses Live; a missing or older catalog cannot answer the question, so the run proceeds and existing drivers keep working. ### Take picture on arrival Works for arms as well as mobile robots. The image is attached to the run and exposed on the node's output as `attachment_uuid`, `file_url` and `captures`, ready to wire into a Call Model or Annotate node. If no camera frame is available the run continues and the node reports `capture_error`. In a Simulation run **against a robot arm**, the picture is what the twin's camera sees in the simulation, even when the same twin is also connected to a real robot. If the simulation is not rendering that camera the node reports `capture_error` rather than substituting the real camera's view. Mobile robots do not yet take an arrival picture in a Simulation run. The capture is performed by the robot's own driver, which a simulated run does not drive, so the node completes with no image and no `capture_error`. Use a Live run when you need the picture. # Spatial Filter node Source: https://docs.cyberwave.com/feature-reference/workflows/spatial-filter Keep only the detections whose reference point falls inside a polygon zone drawn in normalized image coordinates, so it works at any resolution. `spatial_filter` is a stateless workflow node that drops detections that lie outside an author-defined polygon zone. It pairs with [`timed_condition`](./timed-condition) downstream to build zone-based intrusion alerts without per-camera pixel coordinates. Execution context is inferred from the upstream graph: * Wired downstream of a `camera_frame` trigger + `call_model` chain it is compiled into the edge worker as an inline polygon-membership comprehension. * Wired anywhere else it runs in the cloud workflow runner against the detection array of the upstream node. Typical chain for a zone-scoped intrusion alert: ``` trigger (camera_frame) → call_model (YOLO) → anonymize → spatial_filter → timed_condition → send_alert ``` ## Coordinate system Polygons are stored as `[[x, y], ...]` of floats in **normalized \[0..1] image coordinates** — the same space YOLO bounding boxes already use. A zone authored against a 1080p stream keeps working when you swap the camera for a 4K one without any manual remap. Polygons must have at least 3 vertices. ## Inputs | Field | Type | Description | | ------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `detections` | array | Detection results from an upstream `call_model` (or `anonymize` / `annotate` — the implicit-wiring contract carries the detection array through unchanged). Required. | | `polygon` | array | `[[x, y], ...]` in normalized \[0..1] coordinates. ≥ 3 vertices. | | `point_mode` | string | Which part of each detection's bounding box must fall inside the polygon to count as "in". `bbox_bottom_center` (default) for floor-anchored subjects, `centroid` for mid-air things, `any_overlap` if any pixel of the bbox touching the polygon should count. | | `frame` | string | `image` (only mode supported in v1; floor-plan zones are deferred). | | `classes` | array | Optional class allow-list applied before the polygon test. `null` / empty means every detection class is tested. | ## Outputs | Field | Type | Description | | ------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `detections` | array | Subset of input detections that passed the polygon test. | | `count` | number | Length of the filtered detection array — handy for downstream conditional gates. | | `polygon` | array | Echo of the configured polygon (normalized coordinates) so downstream snapshot rendering and the live frontend overlay can draw the ROI without re-fetching the node config. | ## Authoring zones Zones are authored in the workflow editor inspector for the `spatial_filter` node: 1. Add a `Spatial Filter` node from the **Decision & Control** group. 2. Wire a `camera_frame` trigger upstream (typically through a `call_model` that runs detection). 3. In the inspector, click on the polygon canvas to add vertices, drag to move them, double-click to remove (≥ 3 vertices required). 4. Optional: click **Capture frame** to fetch the latest still from the upstream camera trigger and trace the polygon over the actual scene. 5. Pick the **Reference Point** that matches your subjects: `bbox_bottom_center` for people standing on the floor, `centroid` for mid-air objects, `any_overlap` when even a finger crossing the line should count. Once the workflow is **active**, the polygon also renders as a read-only overlay on the twin's WebRTC stream so operators can see which zones are armed. ## Edge implementation The node compiles into a Python comprehension inlined into the generated edge worker (`wf_.py`) — no extra runtime dependencies, no MQTT round-trip per frame. The polygon-membership helper is generated only once even if multiple zones share a worker. See [Edge Workers](/feature-reference/workflows/workers/overview) for the full lifecycle. ## Companion nodes * [`timed_condition`](./timed-condition) — fire only when something has been *inside* the zone for at least N seconds. * [`anonymize`](./anonymize-image) — pair upstream of `spatial_filter` to publish privacy-safe video while still alerting on zone violations. # Timed Condition node Source: https://docs.cyberwave.com/feature-reference/workflows/timed-condition Time-threshold gate: fire when a signal stays active for at least N seconds, then re-arm after a cooldown. Works with detections, booleans and numbers. `timed_condition` is a stateful conditional node that holds the "active" signal for at least `min_duration_s` seconds before firing, then re-arms only after the input has been inactive for at least `cooldown_s` seconds. It is the generalised successor to the original `presence_dwell` node — the dwell semantics are still the default behaviour, but the input now accepts any signal shape (not just detection arrays), so the same primitive applies to non-vision workflows. **Backward compatibility.** Workflows authored before the rename use the legacy `presence_dwell` subtype. The cloud executor and edge codegen continue to accept that string and resolve it to this same schema, so existing zone-based intrusion alerts keep working without edits. New nodes created from the palette use the canonical `timed_condition` subtype. ## When to use this node `detection_event_gate` (the existing class-change gate) emits on the first frame a class appears. That's correct for "person detected at all" alerts but wrong for "person has been loitering in zone A for 10 seconds" — there is no time component in the event-gate state. `timed_condition` is the time-dimension counterpart: | Node | When it fires | | ---------------------------------------- | ---------------------------------------------------------------------- | | `detection_event_gate` (`on_enter`) | On the first frame a target class appears. | | `timed_condition` (`mode = "sustained"`) | On the frame the cumulative "active" duration crosses the threshold. | | `timed_condition` (`mode = "timeout"`) | On the frame the cumulative "inactive" duration crosses the threshold. | | `timed_condition` (`mode = "debounce"`) | Immediately on the first activation, then suppressed for `cooldown_s`. | ## Modes | Mode | Behaviour | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sustained` | Fires once the signal has been continuously active for ≥ `min_duration_s`. Re-arms after `cooldown_s` of inactive signal. | | `timeout` | Watchdog. Fires once the signal has been continuously *inactive* for ≥ `min_duration_s`. Re-arms automatically on the next active frame (cooldown is unused). | | `debounce` | Leading-edge fire with suppression. Fires immediately on the first activation, then suppresses re-fires for `cooldown_s` regardless of signal state. `min_duration_s` is unused. | All three modes share the same per-node state and the same input predicate (active-when-truthy / above-threshold / non-empty), so swapping modes never requires re-wiring the upstream graph. Unknown modes are rejected loudly by the cloud executor and the edge codegen so a stale UI can't silently run the wrong shape. ## Inputs | Field | Type | Description | | ------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `signal` (legacy: `detections`) | array \| boolean \| number | The signal to evaluate. Detection array + non-empty (after the optional class filter) counts as active. Boolean is active when truthy. Number is active when ≥ `threshold`. The port is named `detections` for back-compat with workflows authored before the rename. | | `mode` | string | One of `sustained` (default), `timeout`, or `debounce`. See the **Modes** table above. | | `min_duration_s` | number | Continuous "active" seconds required before the gate fires (`sustained`) or continuous "inactive" seconds before the timeout fires (`timeout`). Ignored by `debounce`. `0` fires on first observation. | | `cooldown_s` | number | Inactive seconds required after firing before the gate re-arms (`sustained`) or suppression window after firing (`debounce`). Ignored by `timeout`, which re-arms on the next active frame. | | `target_classes` | array | Optional class allow-list applied when the signal is a detection array. Empty / `null` matches any class. Ignored for boolean and number signals. | | `threshold` | number | Numeric threshold used when the signal is a number. The signal is active when value ≥ threshold. Default `0`. Ignored for boolean and array signals. | ## Outputs | Field | Type | Description | | -------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `condition_met` | boolean | `true` on the frame the time threshold is first crossed; `false` otherwise. | | `dwell_ms` | number | How long the signal has been continuously active when the gate fires; `0` when not firing. (Kept under the legacy `dwell_ms` name for back-compat with downstream wiring.) | | `matched_detections` | array | Detections from the current frame that passed the `target_classes` filter when the signal is a detection array; empty list otherwise. Handy to forward into `send_alert.metadata` so an operator can see what triggered the gate. | | `first_seen_ts` | number \| null | Monotonic seconds when the current active window started; `null` when the signal is currently inactive. Use it for relative "active for N seconds" math inside the same edge / runner process, not for cross-process correlation. | ## State machines State is keyed on `node.uuid` so two instances on the same workflow run independent timers — typical when one zone tracks people and another tracks vehicles. ### Sustained ``` ┌─────────────────────┐ signal becomes active ┌──────────────────────┐ │ IDLE (re-armed) │ ──────────────────────────▶│ ACTIVE (counting) │ └─────────────────────┘ └──────────────────────┘ ▲ │ │ │ elapsed_ms ≥ min_duration_s │ ▼ │ cooldown_s seconds ┌──────────────────────┐ └──────────────────── of inactivity ─────────│ COOLDOWN (fired) │ └──────────────────────┘ ``` ### Timeout ``` ┌─────────────────────┐ signal goes inactive ┌──────────────────────┐ │ IDLE (re-armed) │ ────────────────────────▶│ COUNTING (inactive) │ └─────────────────────┘ └──────────────────────┘ ▲ │ │ │ elapsed_ms ≥ min_duration_s │ next active frame ▼ └────────────────────────────────────────── ┌──────────────────────┐ │ FIRED (one-shot) │ └──────────────────────┘ ``` The next active frame closes the inactive window and re-arms the gate immediately — there is no cooldown. Designed for "alert if the signal stays absent" patterns (occupancy timeout, missing heartbeat, stale telemetry). ### Debounce ``` ┌─────────────────────┐ signal becomes active ┌──────────────────────┐ │ IDLE (re-armed) │ ─────────────────────────▶│ FIRED │ └─────────────────────┘ └──────────────────────┘ ▲ │ │ │ cooldown_s elapsed │ ▼ │ ┌──────────────────────┐ └────────────────────────────────────────────│ SUPPRESSING │ └──────────────────────┘ ``` Ignores `min_duration_s` and the signal value during the suppression window — re-fires only after `cooldown_s` has elapsed, on the next active frame. ## Authoring In the workflow editor inspector for the `timed_condition` node: * **Mode** — pick `Sustained`, `Timeout`, or `Debounce`. The other knobs grey out automatically when the selected mode ignores them (e.g. `Min Duration` is disabled in `Debounce`, `Cooldown` is disabled in `Timeout`). * **Min Duration (s)** — how long the signal must persist before the gate fires (active for `Sustained`, inactive for `Timeout`). `0` for "fire on first frame" semantics; `5`–`30` for loitering / intrusion alerts; higher for "left unattended" scenarios. * **Cooldown (s)** — for `Sustained`, how long the input must stay inactive after a fire before the gate re-arms. For `Debounce`, the suppression window after the leading-edge fire. Tune to your alert review cadence. * **Target Classes** — optional class allow-list (chips), only used when the upstream signal is a detection array. Leave empty when the upstream `spatial_filter` is already class-scoped. ## Companion nodes * [`spatial_filter`](./spatial-filter) — the canonical upstream for detection-array signals: scope the gate to a polygon zone. * `send_alert` — the canonical downstream: fire an alert with the polygon and elapsed duration baked into the payload. ## Edge implementation `timed_condition` requires an explicit `send_alert` node downstream to publish anything. The legacy implicit-alert path on `call_model` that used to inline a dwell state machine into the generated `wf_*.py` worker has been retired — alert emission now lives entirely in `send_alert` (see [Raising alerts from detections](/feature-reference/workflows/workers/overview#raising-alerts-from-detections)). The dispatcher (`EdgeWorkflowCompiler`) routes any `camera_frame` workflow that contains a `send_alert` node through `WorkflowCodeAssembler` rather than the single-hop `WorkerCodegen` path, and the assembler emits the explicit alert calls. A `timed_condition` wired downstream of `call_model` *without* a trailing `send_alert` is reported as inert at compile time (`WorkerCodegen.warnings` carries the inert-timer text), so the editor can surface the dead-timer condition before the worker is deployed. The cloud workflow runner executes `timed_condition` via `_execute_timed_condition_node` in `src/lib/workflow_utils.py`, which is the canonical implementation of all three modes (`sustained`, `timeout`, `debounce`) and the source of the `min_duration_s` / `cooldown_s` defaults. State is keyed on `node.uuid` and lives in-process — restart the runtime and the timer resets to IDLE. ## End-to-end alert pipeline A common pattern is "polygon → timed condition → email": 1. **Edge perception workflow** (camera\_frame trigger): `camera_frame → call_model → anonymize → spatial_filter → timed_condition`. The edge worker emits one `cw.publish_alert(...)` per gate-fired intrusion event. 2. **Cloud reactive workflow** (alert trigger): `alert_trigger(twin=…, alert_type=detection) → send_email`. The cloud workflow runner wakes on every edge-emitted alert and sends the email — no per-frame cloud cost, only the dwell-gated one-shots. The `timed_condition` cloud executor exists too and behaves identically, but it is intended for cloud-only graphs where detections (or boolean / number signals) are produced inside a single `WorkflowUtils.execute()` call (e.g. fed by a non-camera trigger). It is **not** designed for state to persist across separate alert-triggered cloud executions. # Timer node Source: https://docs.cyberwave.com/feature-reference/workflows/timer Pause a workflow for a set amount of time before the downstream nodes run. The **Timer** (`timer`) node pauses the workflow for a configured amount of time, then lets the nodes connected after it run. Use it to space out actions — for example, wait 30 seconds between two commands, or hold before re-checking a condition. **Palette category:** Decision & Control Flow. Runs on **cloud** workflows and **edge** workers (identical wait duration in both). ## Configuration | Field | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------- | | `duration` | number | Yes | How long to wait, in the selected unit. | | `time_unit` | select | No | `seconds` (default) or `minutes`. | The wait resolves to `duration × 60` seconds for **minutes**, or `duration` seconds for **seconds**. Durations are capped at 24 hours. `duration` must be set before the workflow can be activated. Like any mandatory (`*`) input, a Timer with no duration blocks activation and the editor shows a "Configure Duration" prompt on the node. ## Behavior The Timer simply waits, then completes — the nodes wired after it run next, exactly as they would after any other node. Nothing else is required to "trigger" them. A Timer cannot be placed downstream of a **Camera Frame** trigger: a wait would block the per-frame processing loop. Use it in manual, mission, schedule, or message-triggered workflows. # Twin node Source: https://docs.cyberwave.com/feature-reference/workflows/twin Read a digital twin and its assigned controller policy as structured outputs. The **Twin** (`twin`) node reads a digital twin and its **assigned controller policy** and exposes them as structured outputs. Use it upstream of **Fuzzy Matcher** so voice pipelines know which command strings are valid for that robot, and to surface controller identity/mode to downstream nodes. **Palette category:** Data Sources. Runs on **cloud** and **edge** (edge workers resolve the policy via the Cyberwave API). ## Inspector * **Digital Twin** — combobox selector. * `twin_uuid` is stored in node parameters, not the generic input-mapping row. ## Policy resolution The node resolves the active policy from: 1. Twin `controller_policy` FK, or 2. `twin.metadata.controller_policy_uuid` If neither is set, execution fails with a clear error. ## Outputs | Field | Type | Description | | -------------------- | ------ | ------------------------------------------------------------------------------------------------- | | `name` | string | Twin display name | | `asset` | string | Asset slug from policy metadata (or first linked asset) | | `device` | string | Input device from policy metadata (e.g. `keyboard`) | | `control_actuations` | array | **Locomotion** actuation slugs from `metadata.keyboard_bindings` (`move_forward`, `turn_left`, …) | | `control_labels` | array | Human-readable labels from **all** keyboard bindings | | `controller_name` | string | `metadata.controller_name` on the assigned controller policy | | `controller_type` | string | `metadata.controller_type` on the assigned controller policy | | `control_mode` | string | `metadata.control_mode` on the assigned controller policy | `control_actuations` only includes locomotion slugs (WASD-style). Non-locomotion bindings (lights, camera, `take_photo`) appear in `control_labels` but not in `control_actuations`. ## Fuzzy Matcher wiring | Twin output | Fuzzy Matcher input | Notes | | -------------------- | ------------------- | -------------------------------------------------- | | `control_actuations` | `candidates` | Match STT against actuation slugs (`move_forward`) | | `control_labels` | `candidates` | Match STT against spoken labels (`Move Forward`) | ## Execution targets | Target | Notes | | --------- | ---------------------------------------------------------------------- | | **Cloud** | `WorkflowUtils._execute_twin_node` — reads twin + policy from Postgres | | **Edge** | Code emitter calls `client.twins.get` + controller-policies API | # Virtual Controller node Source: https://docs.cyberwave.com/feature-reference/workflows/virtual-controller Dispatch controller actuations to a twin over MQTT from workflow automation. The **Virtual Controller** (`virtual_controller`) resolves a **command** string against the **keyboard controller policy assigned to a digital twin** and publishes the matching actuation on `cyberwave/twin/{uuid}/command`. The MQTT payload matches keyboard teleoperation (`KeyboardTeleoperationController` / `useMQTTTwin.publishCommand`) — nothing is hardcoded per robot; bindings come from the twin's policy at runtime. **Palette category:** Actuation. Runs on **cloud** (Celery MQTT) and **edge** (worker `client.mqtt.publish`). Locomotion uses the MQTT command topic, not WebRTC; media streaming stays on separate channels. ## Voice-to-actuation pipeline ``` audio_track → audio_assistant (optional VAD) → wake_word_engine (optional) → call_model (STT) → fuzzy_matcher ← twin (control_actuations / control_labels) → conditional (optional, branch on matched) → virtual_controller → cyberwave/twin/{uuid}/command ``` | Step | Node | Key wiring | | ---- | ---------------------- | --------------------------------------------------------------------------- | | 1 | **Twin** | Select target twin → wire `control_actuations` → Fuzzy Matcher `candidates` | | 2 | **Call Model** | STT `result` → Fuzzy Matcher `query` | | 3 | **Fuzzy Matcher** | `match_string` → Virtual Controller `command` (when `match` is true) | | 4 | **Virtual Controller** | Same twin as Twin node → publishes resolved actuation | ## Inputs | Field | Type | Required | Description | | ----------- | ------ | -------- | -------------------------------------------------------------------------------------------------- | | `twin_uuid` | string | Yes | Twin whose controller policy resolves commands. Set in inspector (Twin combobox). | | `command` | string | Yes | Label or actuation to dispatch. Wire from Fuzzy Matcher `match_string` or another upstream string. | Precedence: wired input mapping → node parameters. ### Command matching The node accepts **either** form (normalization is shared with Fuzzy Matcher): | Input | Resolves to actuation | | ---------------- | --------------------- | | `camera_right` | `camera_right` | | `Camera Right` | `camera_right` | | `W` (single key) | binding for that key | Resolution order: 1. Exact actuation (case / punctuation insensitive) 2. Exact human label 3. Keyboard key 4. Substring containment (label inside longer STT phrase) Bindings are collected from: * `metadata.keyboard_bindings` (`actuation`, `label`, `key`, optional `playground` data) * `metadata.display_config.widgets` (button `command`, slider `command`) * **Universal keyboard** policies with `supports_locomotion` and no bindings → default WASD locomotion actuations (`move_forward`, `turn_left`, …) ## Inspector * **Digital Twin** — combobox; policy is never hardcoded in the node. * **command** — wire from upstream (typically Fuzzy Matcher `match_string`). ### Inspector preview When a twin is selected, the panel shows: | Section | Contents | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | **Twin** | Name, slug, UUID, environment, asset UUID | | **Controller** | Policy name, type (`teleop`), control mode (`command` / `velocity` / `joint_control`), input device, asset slug, policy UUID | | **Forwardable commands** | Scrollable list: actuation slug, label, optional key | Use this list to verify what voice commands the pipeline can dispatch before running the workflow. ## MQTT payload Published to `cyberwave/twin/{twin_uuid}/command`: ```json theme={null} { "source_type": "tele", "command": "move_forward", "data": {}, "timestamp": 1710000000.0 } ``` | Field | Cloud workflow | Edge worker | | ------------- | --------------------------------------------------------- | ----------- | | `source_type` | `tele` (live) or `sim_tele` (simulation execution target) | `edge` | | `command` | Resolved **actuation** slug (not the raw input label) | | | `data` | From binding `playground` when present, else `{}` | | Same shape as manual keyboard teleop so edge drivers and simulators consume workflow commands without special cases. ## Outputs | Field | Type | Description | | -------------------- | ------- | ------------------------------------------------------- | | `command` | string | Resolved actuation that was last sent on MQTT | | `available_commands` | array | `{actuation, label, key}` for every forwardable binding | | `twin_name` | string | Twin display name | | `controller_name` | string | Policy name | | `controller_type` | string | e.g. `teleop` | | `matched` | boolean | `true` when resolution succeeded | | `sent` | boolean | Cloud: MQTT queued; edge: publish attempted | On resolution failure the node raises an error (unknown command, missing policy, missing twin). ## Execution targets | Target | Behavior | | --------- | ------------------------------------------------------------------------------------------------------------- | | **Cloud** | `run_virtual_controller_node` → `send_update_to_mqtt.delay` | | **Edge** | Emitter caches policy per twin (`_CW_VC_POLICY_CACHE`) via API on first use; `client.mqtt.publish` with QoS 0 | Edge workers **save** the resolved controller snapshot (UUID, name, metadata, parsed `entries`) in process memory so repeat commands on the same twin do not re-fetch the policy every frame. ## Recommended Conditional gate Only run Virtual Controller when Fuzzy Matcher succeeded: ``` fuzzy_matcher.match → conditional (equals true) → virtual_controller ``` Pass `fuzzy_matcher.match_string` into `virtual_controller.command` on the true branch. ## Dependencies | Layer | Requirement | | ------------------ | ------------------------------------------------------------------------------------- | | **Compile server** | No ML extras. `paho-mqtt` and `httpx` are base Django/SDK deps. | | **Edge worker** | Base `cyberwave` — `client.twins.get`, controller-policies API, `client.mqtt.publish` | | **edge-sync** | No `model_requirements` (no ML weights) | `rapidfuzz` is only required on the **Fuzzy Matcher** node upstream, not on Virtual Controller. Full voice-pipeline matrix: [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies). ## Controller policy examples Command-mode UGV policies (`control_mode: "command"`) define bindings like: ```json theme={null} { "key": "W", "label": "Forward", "actuation": "move_forward", "continuous": true } ``` Virtual Controller sends `move_forward` on MQTT when the pipeline passes `"Forward"`, `"move_forward"`, or fuzzy-matched variants. See seeded policies in `seed_controllers.py` (e.g. `controller:ugv-beast:v1`). Universal keyboard (`controller:keyboard-locomotion:v1`) has no per-asset bindings in seed data; the node uses built-in locomotion defaults when `supports_locomotion` is true. ## Related nodes * **Twin** — supplies Fuzzy Matcher `candidates` from `control_actuations` / `control_labels` * **Fuzzy Matcher** — maps noisy STT (uncertain string) → `match_string` from a source-of-truth string or array * **Call Model** — STT text → Fuzzy Matcher `query` * **Conditional** — gate on `matched` * **Send MQTT** — generic publish; Virtual Controller is purpose-built for controller actuations # Wake Word — models & compile Source: https://docs.cyberwave.com/feature-reference/workflows/wake-word-engine/models-and-compile How selected openWakeWord models are downloaded before edge deploy Wake Word workflows only download the models the author selected — not every file in the openWakeWord catalog. ## Compile-time provision (cloud) When you **compile** or **edge-sync** a workflow that contains a Wake Word Engine node, `WorkflowCodeAssembler` calls: ```python theme={null} openwakeword.utils.download_models(model_names=["alexa", ...]) ``` Then verifies load with `Model(wakeword_models=[...])` and records `prediction_keys` from `oww_model.models.keys()`. | Outcome | Meaning | | -------------------------- | --------------------------------------------------------------------------------------- | | Compile succeeds + warning | `openWakeWord models downloaded for edge: alexa, ...` | | Compile fails | `openwakeword` not installed on Django (`ml-wakeword` extra), or download/network error | | `GET /compile` field | `openwakeword_models: ["alexa"]` lists normalized model ids | The Django compile host must have `openwakeword` and `onnxruntime` in `cyberwave-backend/requirements/base.txt`. Rebuild the Django Docker image after adding them. See [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies). ### Compile-server packages | Package | Purpose | | --------------------- | -------------------------------------- | | `openwakeword>=0.6.0` | Model download + load probe at compile | | `onnxruntime>=1.16.0` | openWakeWord runtime | ## Generated worker (edge) The compiled `wf_.py` module begins with: ```python theme={null} _CW_WW_WORKFLOW_WAKE_WORDS = ['alexa'] # download_models(model_names=_CW_WW_WORKFLOW_WAKE_WORDS) _cw_ww_ensure_models_downloaded(_CW_WW_WORKFLOW_WAKE_WORDS) ``` Models are fetched again at worker import (before hooks run) and once more when the engine singleton is created. ## Edge-sync metadata Each Wake Word node contributes to `model_requirements`: ```json theme={null} { "edge_runtime": "openwakeword", "edge_package": "ml-wakeword", "edge_model_path": "openwakeword/pretrained", "wake_word_models": ["alexa"] } ``` Edge operators use this to confirm the worker image and cache contain the required weights. ## Edge worker image `cyberwaveos/edge-ml-worker` Dockerfile runs: ```bash theme={null} python3 -c "import openwakeword; openwakeword.utils.download_models()" ``` at build time (\~20 MB all six built-in models). Workflow-specific `download_models(model_names=[...])` still runs for clarity and custom images. ## Custom images (air-gapped) ```dockerfile theme={null} RUN pip install openwakeword onnxruntime RUN python3 -c "import openwakeword; openwakeword.utils.download_models()" ``` Or download only what you need: ```python theme={null} import openwakeword openwakeword.utils.download_models(model_names=["alexa", "hey_jarvis"]) ``` ## Threshold vs compile **Detection threshold** is a runtime node parameter (default **0.5**, one value for all selected wake words). It is embedded in compiled `wf_*.py` as `threshold=...` on the engine singleton. Changing threshold only requires **save → compile → sync** — no extra model download. ## After changing wake words or threshold 1. Save the Wake Word node in the editor (wake words and/or **Detection Threshold**). 2. **Compile** the workflow (validates models download). 3. **Sync** to the edge environment. 4. Restart the workflow worker container. 5. Confirm logs: `prediction_keys=['alexa']` (not `alexa_v0.1`) and `threshold=0.50` in init / detection lines. # Wake Word Engine Source: https://docs.cyberwave.com/feature-reference/workflows/wake-word-engine/overview OpenWakeWord on/off switch for voice-activated edge workflows The **Wake Word Engine** is an edge-only voice trigger. It sleeps until it hears the wake word, then streams **PCM int16 @ 16 kHz mono** downstream (typically to [Call Model / Whisper](/feature-reference/ml-models/speech-to-text)) until you stop speaking. Internally uses [OpenWakeWord](https://github.com/dscripka/openWakeWord). ## Typical pipeline ``` Audio Track (80 ms buffer) → Wake Word Engine → Call Model (Whisper) → Send Alert ``` Set **Audio Track** buffer preset to **Wake Word (80 ms)** — not Speech-To-Text (4 s). A 4 s upstream buffer only invokes scoring about once every 4 seconds and makes short phrases like "alexa" easy to miss. Compile rejects Audio Track `speech-to-text` → Wake Word Engine. | Stage | Recommended buffer | | ---------------------------------------- | ----------------------------------------- | | Audio Track → Wake Word (input) | **Wake Word** — 80 ms / 1,280 samples | | Wake Word → Whisper (output while AWAKE) | **Speech-To-Text** — 4 s / 64,000 samples | ## Built-in wake words (only these six) Legacy ids such as `hey_siri` are **not** in openWakeWord v0.5.x and are stripped at compile and runtime. | Model ID | Phrase to speak | | ------------- | ----------------------- | | `alexa` | "alexa" | | `hey_mycroft` | "hey mycroft" | | `hey_jarvis` | "hey jarvis" | | `hey_rhasspy` | "hey rhasspy" | | `weather` | "what's the weather" | | `timer` | "set a 10 minute timer" | Select multiple words in the UI — the engine activates on **any** of them. ## Detection threshold One **Detection Threshold** in the workflow editor applies to **every** selected wake-word model (default **0.5**, range 0–1). A frame triggers AWAKE when **any** loaded model’s score is ≥ that value. | Setting | Where | Default | | ------------------- | ------------------------------------- | ------- | | Detection Threshold | Wake Word node → Detection Parameters | `0.5` | There is no per-model threshold override in the engine — tune this single knob if a phrase is too sensitive or too hard to trigger. Pretrained models do not peak at the same level on identical audio. For example, committed test clips often score **\~1.0** for `alexa`, **\~0.68** for `hey_mycroft`, and **\~0.41** for `hey_jarvis`. If `hey_jarvis` (or `hey_rhasspy`) rarely fires at **0.5**, lower the threshold (e.g. **0.35–0.40**) or switch models — do not expect the engine to auto-adjust per model. ## Two-state machine ### SLEEPING * Audio is scored in **80 ms** frames (1,280 samples @ 16 kHz). * Downstream nodes receive no speech audio (only state metadata). * A **lookback deque** (default 500 ms) is used internally for detection only — it is **not** forwarded to STT. * When any selected model score ≥ **threshold** (default 0.5), the engine switches to **AWAKE**. ### AWAKE * After detection, the engine **skips** the wake phrase (default **500 ms**, **Wake Word Trim**) then buffers command-only audio. * One **audio** output is emitted per session (after silence timeout or listening limit), without the wake word in the PCM. * Listening ends per **listening policy** (see below), then state returns to SLEEPING. ## Prediction keys (important) openWakeWord stores files like `alexa_v0.1.onnx`, but `predict()` returns scores under short keys such as `alexa`. Compiled workers use `prediction_keys = list(oww_model.models.keys())` so scores are read correctly. If logs show `words=['alexa_v0.1']` without `prediction_keys=['alexa']`, the edge worker is **stale** — recompile and sync the workflow. ## Model download (three layers) Only the wake words selected in the workflow are provisioned — not the full catalog. | When | What runs | | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Workflow compile** (cloud) | `openwakeword.utils.download_models(model_names=[...])` + load probe. Fails compile if `openwakeword` is missing on Django or download fails. `/compile` returns `openwakeword_models`. | | **Worker import** (edge) | Top of `wf_*.py`: `download_models(model_names=_CW_WW_WORKFLOW_WAKE_WORDS)` then `_cw_ww_ensure_models_downloaded(...)`. | | **Engine init** (edge) | First audio frame: same download (idempotent) before `Model(wakeword_models=...)`. | Edge-sync `model_requirements` includes `wake_word_models: ["alexa", ...]` and `edge_package: ml-wakeword`. The official `cyberwaveos/edge-ml-worker` image also pre-bakes all built-in models at image build time for air-gapped use. ## Configuration | Parameter | Default | Description | | -------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | Wake Words | `hey_mycroft` | Multi-select built-in models (see table above). | | Detection Threshold | `0.5` | Min score \[0, 1] for **all** selected models to enter AWAKE (workflow editor → Detection Parameters). | | Limit listening time | Off | When on, forward audio only for N seconds (default **2 s**), then SLEEPING. When off, forward until **silence timeout** (default 1.5 s). | | Silence Timeout (s) | `1.5` | Used when limit listening is **off**. | | Wake Word Trim (ms) | `500` | Audio discarded after detection before STT (excludes wake phrase). | | Output Buffer Preset | `wake-word` | Chunks emitted while AWAKE (see presets). | | Digital twin (signaling) | — | Twin that receives MQTT/Zenoh assistant commands (see below). | | Play start/stop assistant sounds | On | Publish signaling when forwarding starts/stops. | | Feedback target | `Desktop` | Where the assistant feedback plays: `Desktop` (MQTT → browser), `Edge` (Zenoh → on-device speaker), or `Both`. | ### Output buffer presets (while AWAKE) | Preset | Size | Use case | | ----------------- | ------------- | ---------------------------------------------------------- | | `voice-assistant` | 32 ms (512) | Another VAD / Audio Assistant | | `wake-word` | 80 ms (1,280) | Low-latency chaining | | `speech-to-text` | 4 s (64,000) | **Whisper / Call Model STT** (recommended after wake word) | | `custom` | User seconds | Arbitrary chunk size | ## Assistant sound signaling When **Play start/stop assistant sounds** is enabled and a **digital twin** is selected (same twin as the Audio Track microphone), the engine emits two events per AWAKE session: | Event | Command | | ------------------------------------- | ----------------- | | Wake word detected, forwarding starts | `start_assistant` | | Forwarding ends (timeout or limit) | `stop_assistant` | Both events carry the same JSON payload: ```json theme={null} { "source_type": "edge", "source_subtype": "wake_word_engine", "command": "start_assistant" } ``` `source_type` is `edge` when the workflow runs on the edge (default for Wake Word Engine) and `tele` when the workflow runs on the cloud. `source_subtype` is the wake word node name (defaults to `wake_word_engine`), following the [`CwProcessor`](https://github.com/cyberwave-os) source subtype convention. ### Feedback target A **Feedback target** sidebar toggle controls where the audio plays: | Option | Transport | Subscriber | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | | **Desktop** (default) | MQTT — `{prefix}cyberwave/twin/{TWIN_UUID}/commands/assistant_signaling` | Environment viewer in the browser (`/sounds/assistant/start-assistant.mp3`, `end-assistant.mp3`) | | **Edge** | Zenoh — `{prefix}/{TWIN_UUID}/data/commands/assistant_signaling` (built via [`build_key`](https://github.com/cyberwave-os/cyberwave-sdks)) | On-edge speaker driver subscribed to the Zenoh channel | | **Both** | MQTT + Zenoh | Browser and edge speaker react simultaneously | Edge and Both require a speaker physically connected to the edge device, plus an edge speaker driver subscribing to the Zenoh `commands/assistant_signaling` channel for the twin. The frontend handler is `cyberwave-frontend/lib/workflows/assistant-signaling-sounds.ts` (`handleAssistantSignalingCommand`), wired into `useMQTTTwin` for environment viewers. ## Input formats Adapted automatically to int16 @ 16 kHz mono: | Format | Source | | ----------------------- | -------------------------------------------- | | NumPy int16 / float32 | Audio Track `audio`, Audio Assistant `audio` | | Raw PCM bytes | `audio` or `audio_bytes` on upstream dict | | WAV bytes (RIFF) | Audio Track `audio_bytes` | | WAV file path (`*.wav`) | Batch / offline tests | ## Output (only after score ≥ threshold) | Field | Description | | ------------------ | ---------------------------------------------------------- | | `audio` | Command-only int16 PCM @ 16 kHz mono (wake phrase trimmed) | | `wake_word` | Trigger id (e.g. `alexa`) — metadata only, not in `audio` | | `wake_word_score` | Confidence at detection | | `wake_word_scores` | e.g. `{"alexa": 0.512}` | While SLEEPING, outputs contain state only (`state`, `is_speaking`) — no speech `audio`. ## Logging on edge At **INFO** (worker log level): * `Wake Word Engine initialized: wake_words=[...] prediction_keys=[...]` * Periodic `Wake word listening scores=...` (\~every 2 s while listening) * `Wake word detected: 'alexa' scores={'alexa': 0.512} threshold=0.50, switching to AWAKE` Set `CYBERWAVE_WORKER_LOG_LEVEL=DEBUG` for per-frame scores above 0.15. ## Dependencies | Layer | Requirement | | ------------------ | ------------------------------------------------------------------------------------------------------------------------ | | **Compile server** | `openwakeword`, `onnxruntime` — see [models & compile](/feature-reference/workflows/wake-word-engine/models-and-compile) | | **Edge worker** | `cyberwave[ml-wakeword]` | | **edge-sync** | `edge_package: ml-wakeword`, `wake_word_models: [...]` | [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies) lists all voice nodes and STT catalog extras. ## Related Full compile + edge matrix Compile-time download and edge-sync requirements WAV fixtures and offline detection tests Upstream buffer presets Shared PCM format # Wake Word — testing Source: https://docs.cyberwave.com/feature-reference/workflows/wake-word-engine/testing Offline WAV tests and live edge worker diagnostics ## Detection threshold Production and offline tests use the same rule: **score ≥ workflow threshold** (default **0.5**). The Wake Word node exposes one **Threshold** field in the editor — it applies to all selected models (`alexa`, `hey_jarvis`, etc.), not per model. Pass `--threshold` to offline tools to mirror the value saved on the node: ```bash theme={null} # Match a workflow node set to 0.35 for hey_jarvis python manage.py test_wake_word_wav clip.wav --model hey_jarvis --threshold 0.35 ``` | Model (fixture) | Typical peak on committed WAV | Often works at default 0.5? | | --------------- | ----------------------------- | ---------------------------- | | `alexa` | \~1.0 | Yes | | `hey_mycroft` | \~0.68 | Yes | | `hey_jarvis` | \~0.41 | Often no — try **0.35–0.40** | ## Offline WAV test (edge worker) Use a recording that contains the wake phrase (e.g. someone saying "alexa"). Copy into the worker container and run the bundled script: ```bash theme={null} docker cp scripts/test_wake_word_wav.py cyberwave-worker-:/tmp/ docker cp alexa-sample.wav cyberwave-worker-:/tmp/ docker exec -it cyberwave-worker- python3 /tmp/test_wake_word_wav.py \ /tmp/alexa-sample.wav --wake-words alexa --threshold 0.5 ``` Success (management command on compile host): ```text theme={null} HIT @ 1.28s scores={'alexa': 0.512} (threshold=0.5) Done: frames=... max_score=0.9998 @ ...s hits_above_threshold=1 ``` On a live edge worker, look for: ```text theme={null} Wake word detected: 'alexa' scores={'alexa': 0.512} threshold=0.50, switching to AWAKE ``` The script: * Resamples any WAV rate/channels to **16 kHz mono int16** * Scores **80 ms** frames (1,280 samples) * Uses the same `Model(wakeword_models=[...])` keys as production ## Django management command (compile host) If `openwakeword` is installed on the backend container: ```bash theme={null} docker compose -f local.yml exec django python manage.py test_wake_word_wav \ src/app/tests/fixtures/audio/alexa_sample.wav --model alexa --threshold 0.5 docker compose -f local.yml exec django python manage.py test_wake_word_wav \ src/app/tests/fixtures/audio/hey_mycroft_sample.wav --model hey_mycroft --threshold 0.5 docker compose -f local.yml exec django python manage.py test_wake_word_wav \ src/app/tests/fixtures/audio/hey_jarvis_sample.wav --model hey_jarvis --threshold 0.5 ``` Committed fixtures under `cyberwave-backend/src/app/tests/fixtures/audio/` cover alexa, hey\_mycroft, and hey\_jarvis. * **Pytest** (`test_wake_word_wav_detection.py`, `@pytest.mark.integration`): asserts each fixture reaches an expected **peak** score (not that 0.5 always fires for every model). * If `hey_jarvis` at `--threshold 0.5` prints `No frame reached threshold`, lower `--threshold` to match your workflow node or inspect `max_score` in the summary line. ## Live workflow checklist | Check | Expected | | --------------------- | ---------------------------------------------------------------- | | Audio Track buffer | **Wake Word (80 ms)** — codegen shows `_CwAudioFifoBuffer(1280)` | | Worker init log | `wake_words=['alexa'] prediction_keys=['alexa']` | | Say wake phrase | `Wake word detected: 'alexa' scores={'alexa': 0.5+}` | | Send Alert downstream | Alert name = detected wake word | | Assistant signaling | `start_assistant` / `stop_assistant` on twin MQTT topic | ## Common failures | Symptom | Cause | Fix | | ------------------------------------------ | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | No detection, scores always 0 | Stale worker using `alexa_v0.1` prediction keys | Recompile + sync | | Scores rise but never cross threshold | Threshold too high for that model (common with `hey_jarvis` at 0.5) | Lower **Detection Threshold** on the node; confirm with `test_wake_word_wav` and `max_score` | | No logs from wake word node | Audio Track 4 s buffer | Set Wake Word (80 ms) buffer | | `Could not find pretrained model hey_siri` | Removed model still in saved params | Re-save node; pick a built-in word | | Compile error: openwakeword not installed | Django image lacks ml-wakeword | Install on compile host or compile from CI with deps | | No assistant sounds | Twin not set on Wake Word node or FE not on environment | Enable signaling + select microphone twin | ## Log levels ```bash theme={null} # docker-compose or worker env CYBERWAVE_WORKER_LOG_LEVEL=INFO # detection + periodic score heartbeat CYBERWAVE_WORKER_LOG_LEVEL=DEBUG # per-frame scores when best ≥ 0.15 ``` ## Regression tests (repo) Backend (Docker): ```bash theme={null} cd cyberwave-backend docker compose -f local.yml exec -T django pytest \ src/app/tests/test_wake_word_engine_emitter.py \ src/app/tests/test_wake_word_engine_inputs_outputs.py ``` Frontend: ```bash theme={null} cd cyberwave-frontend pnpm test:run __tests__/openwakeword-models.test.ts __tests__/workflow-audio-chain.test.ts ``` Integration WAV test (requires openwakeword in test env): `test_wake_word_wav_detection.py` (marked `@pytest.mark.integration`). # Edge Bench Source: https://docs.cyberwave.com/feature-reference/workflows/workers/bench Measure Zenoh SDK hot-path performance on an edge device and compare against a per-device baseline. `cyberwave edge bench` micro-benchmarks the Zenoh SDK hot paths on whichever machine it runs on — header pack, sample decode, stats accounting, sequence numbering — and compares every metric against a baseline shipped for the detected device class. It prints a device fingerprint, a results table with `Baseline ops/s` / `Delta` / `Status` columns, and a PASS/FAIL report card. ## When to use it * Sanity-check a freshly-provisioned edge device (Jetson, Raspberry Pi, mini-PC) against a known-good reference. * Gate merges in CI on reference hardware: the command exits `2` when any metric regresses beyond the threshold. * Validate performance after kernel, Python, NumPy, or Zenoh upgrades. ## Run it ```bash theme={null} # Default run, auto-selects the baseline for this device class. cyberwave edge bench # Pin to CPU 0 for quieter numbers, dump the full result as JSON. cyberwave edge bench --pin --output /tmp/bench.json # Skip comparison (raw numbers only). cyberwave edge bench --no-compare ``` The device class is auto-detected (`jetson-orin-nano`, `rpi-5`, `x86-laptop`, `apple-silicon-m4`, ...) from `/proc/device-tree/model`, `/etc/nv_tegra_release`, `sysctl -n machdep.cpu.brand_string` (macOS), and `platform.machine()`. On Apple Silicon the chip generation is parsed from the brand string and emitted as `apple-silicon-m1` … `apple-silicon-m4` (Pro / Max / Ultra variants share a tier). Baselines are shipped inside the CLI package, and the loader walks from the specific slug up to a generic fallback — e.g. `apple-silicon-m4` tries `apple-silicon-m4.json` → `apple-silicon.json` → `generic-arm64.json`, so new generations degrade gracefully. Use `--baseline ` to override. ## Bless a baseline for a new device class Run the bench on real reference hardware and write a baseline file the CLI will pick up: ```bash theme={null} cyberwave edge bench \ --rounds 500000 --warmup 20000 --repeat 5 --pin \ --save-baseline ./jetson-orin-nano.json ``` The file name must match the `device_class` slug the fingerprint reports — e.g. `apple-silicon-m4.json` on an M4 / M4 Pro / M4 Max MacBook. Ship the file inside the CLI package's `bench_baselines/` directory and flip `"provisional": false` once you're happy with the numbers. On macOS the `--pin` flag is a no-op; plug in power, disable Low Power Mode, and close background apps before blessing to avoid thermal throttling. ## Key flags | Flag | Default | Purpose | | ------------------------ | -------- | ------------------------------------------------------------- | | `--rounds / -n` | `100000` | Iterations per timed pass. | | `--warmup` | `2000` | Un-timed warmup before each benchmark. | | `--repeat` | `3` | Timed passes; the median is reported. | | `--threshold` | `0.15` | Regression threshold (fraction). | | `--baseline ` | - | Override the auto-selected baseline. | | `--save-baseline ` | - | Persist this run's metrics as a baseline. | | `--output ` | - | Persist the full run result (fingerprint + metrics + deltas). | | `--pin` | `false` | Pin the bench to CPU 0 (Linux only). | | `--no-compare` | `false` | Skip baseline lookup and comparison. | ## Exit codes * `0` — every metric within threshold (or no baseline available). * `2` — one or more metrics regressed beyond `--threshold`. ## Related Install and manage Cyberwave Edge Core. Run ML workers that consume the same Zenoh data plane this bench measures. # Annotate & anonymize nodes Source: https://docs.cyberwave.com/feature-reference/workflows/workers/filter-frame Anonymize or annotate camera frames in a UI-built workflow, no Python needed: the worker rewrites or overlays the camera driver's WebRTC stream. ## Overview `annotate` and `anonymize` are unified workflow nodes. When wired downstream of a `Camera Frame` trigger + `Call Model` chain they are compiled into the **edge worker** (not the cloud) and transform each camera frame in place. They exist to let you build the same kind of pipeline that previously required a hand-edited `~/.cyberwave/workers/.py` — pixelating people for privacy, drawing detection overlays for a kiosk display, etc. — entirely from the workflow editor in the UI. **The two nodes ride different wire contracts.** `anonymize` rewrites pixels and publishes the resulting frame to `FILTERED_FRAME_CHANNEL` (`frames/filtered`); the camera driver substitutes that frame into the WebRTC stream — but only when the per-twin **Privacy Frame Filter** (`frame_filter_enabled`) is on, since the substitution is privacy-fail-closed. `annotate` instead publishes a small JSON overlay spec to `FRAME_OVERLAY_CHANNEL` (`frames/overlay`); the driver subscribes to that channel unconditionally and composites the boxes onto every frame, so **annotate works regardless of the privacy flag**. If you only have an annotate node, leave the flag off. These same node types also run in the cloud workflow runner when wired off a non-camera-frame trigger (e.g. a webhook feeding an `image_url`). The cloud variant is documented at [`anonymize`](/feature-reference/workflows/anonymize-image); both paths share the same pixelation / bbox-drawing algorithms. On a camera-frame chain, both nodes always run **after** a `Call Model` node and **before** the frame leaves the edge. `anonymize` publishes the rewritten pixels on `FILTERED_FRAME_CHANNEL` (driver substitutes into WebRTC, gated on the privacy flag); `annotate` publishes its styled overlay spec on `FRAME_OVERLAY_CHANNEL` (driver composites unconditionally). ```mermaid theme={null} flowchart LR Trigger["Camera Frame trigger"] --> CallModel["Call Model
e.g. yolov8n"] CallModel --> Anon["Anonymize
target_classes=[person]
mode=pixelate"] CallModel --> Ann["Annotate (optional)
line_width=2"] Anon -. substituted pixels .-> SubCh[("frames/filtered
(gated on frame_filter_enabled)")] Ann -. overlay JSON .-> OvCh[("frames/overlay
(always composited)")] SubCh --> Driver["Camera driver → WebRTC"] OvCh --> Driver ``` ## Node types | Node | Palette label | What it draws | | ----------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `anonymize` | **Anonymize** | Pixelates / blurs / redacts / boxes the bounding region of every detection in `target_classes`. | | `annotate` | **Annotate** | Draws coloured bounding boxes and a `label · confidence` caption for every detection in `target_classes` (or all detections when the list is empty). | You can chain them in either order: a workflow with both nodes produces a frame where people are pixelated AND every other detection has a labelled box. Wire order between `annotate` and `anonymize` no longer affects the encoded stream — they ride independent channels — so the workflow editor accepts both `annotate → anonymize` and `anonymize → annotate`. Fan-out (a single source on a camera-frame chain wired into more than one enabled `annotate` / `anonymize`) is rejected at codegen time with a clear error — the published frame and overlay are a single artefact per twin, so multiple branches would be silently collapsed. Cloud-only sub-graphs in the same workflow are not subject to this rule. ### Anonymize parameters | Parameter | Type | Default | Notes | | ---------------- | ---------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `target_classes` | `string[]` | `["person"]` | Class labels to anonymise. Empty list is a no-op. | | `mode` | `string` | `"pixelate"` | One of `pixelate`, `blur`, `redact`, `bbox`. | | `pixel_size` | `int?` | adaptive | Pixel block edge length in pixels. Omit to let the helper choose based on the bounding box size. | | `fallback` | `string` | `"black"` | Edge-only. What the worker publishes when no detection matches `target_classes`. One of `black`, `raw`, `hold_last`. See [On Empty Detections fallback](#on-empty-detections-fallback) below. | Internally this maps onto `cyberwave.vision.blank_persons(frame, results.detections, labels=target_classes, mode=mode, pixel_size=pixel_size)`. We use `blank_persons` rather than `anonymize_frame` so pose-model keypoints don't get unexpectedly overlaid on top of the mosaic — the UI labels this node "Anonymize" and users don't expect skeleton lines to appear. If you want both anonymisation *and* a skeleton overlay, call `anonymize_frame` from a hand-written worker. #### On Empty Detections fallback `blank_persons` only obscures bbox regions for detections in `target_classes`, so on a frame where the model returns *no* matching detections (occluded subject, sub-threshold confidence, transient miss) the resulting `_frame` is byte-for-byte identical to the raw capture. Publishing that to `FILTERED_FRAME_CHANNEL` would silently leak un-anonymized pixels through the WebRTC stream, so the edge worker doesn't — instead, the per-node `fallback` parameter says what to publish on the empty-detection branch: | Value | What the worker publishes on misses | Use when | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `black` (default) | A `np.zeros_like(frame)` black frame. **Privacy fail-closed.** | The default. Pick this whenever the camera scene contains anything sensitive that a model miss would reveal. | | `raw` | The raw camera frame, un-anonymized. **Operator opt-in privacy regression.** | The camera scene is non-sensitive on its own and "always show the live scene" is a product requirement (e.g. a kiosk that pixelates passersby but should never go black when the lobby is empty). | | `hold_last` | Nothing — the worker skips the publish. The camera driver's freshness window (`frame_filter.py`) holds the last filtered frame until staleness, then falls back to its own black on the driver side. | You want a brief "stick" on the last anonymized frame across a transient miss without giving up the privacy contract on extended ones. | When multiple anonymize nodes are chained on the same frame, the **most-restrictive `fallback` wins** (`black` > `hold_last` > `raw`) so a downstream `raw` can't silently weaken an upstream `black`. Resolution lives in `worker_codegen.py::_resolve_anonymize_fallback`. ### Annotate parameters | Parameter | Type | Default | Notes | | ---------------- | ---------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `target_classes` | `string[]` | `[]` | Class labels to annotate. **Empty means "draw every detection"** (matches the SDK helper's `labels=None` default). | | `line_width` | `int` | `2` | Bounding box stroke width in pixels. | | `font_size` | `int` | `14` | Caption font size in pixels (cloud convention). On the edge the codegen translates it into OpenCV's `font_scale` automatically (14 px → \~0.5 scale at `FONT_HERSHEY_SIMPLEX`). | | `mask_alpha` | `float` | `0.35` | Translucency of the segmentation mask fill (`0` disables fill, `1` is opaque). Used only when the upstream model emits per-detection masks (e.g. YOLO-seg). | | `mask_outline` | `bool` | `true` | Trace the segmentation contour on top of the fill. Independent of `line_width`, which still controls the axis-aligned bbox. | | `mask_format` | `string` | `"polygon"` | Wire format for masks. `polygon` (default) is compact and renders natively on the edge driver; `png` matches the cloud structured-action contract; `polygon+png` emits both for downstream cloud post-processing. | On the edge this maps onto `cyberwave.vision.build_overlay_payload(results.detections, labels=target_classes_or_None, line_width=..., font_size=..., mask_alpha=..., mask_outline=..., mask_format=...)`, which the worker publishes on `FRAME_OVERLAY_CHANNEL`. The driver reads the same `font_size` / `line_width` from the payload's `style` block and draws the boxes at WebRTC encode time. (The legacy `cyberwave.vision.annotate_detections` numpy helper is still exported for hand-written workers that draw on a frame buffer directly — the workflow node no longer uses it.) segmentation overlay rendering is v1. The polygon path emits each detection's largest external contour (up to \~64 points) and silently drops holes / secondary blobs. Models that need pixel-accurate masks (e.g. dense semantic segmentation, panoptic) should use `mask_format="png"` and post-process cloud-side. ## Wiring rules On a camera-frame chain, an `annotate` / `anonymize` node MUST have a `Call Model` somewhere in its upstream lineage. The workflow editor enforces this in two places: * **Connection-time:** dragging a `Camera Frame` trigger directly onto a non-`Call Model` target shows an "Invalid connection" toast and refuses the edge. * **Graph-level:** any `annotate` / `anonymize` node on a camera-frame chain whose ancestors don't include a `Call Model` (e.g. because the upstream model was deleted later) is decorated with a yellow warning triangle in the canvas, and the worker codegen rejects the workflow with a `WorkerCodegenError`. The cloud variant (e.g. `webhook → call_model → annotate`) does not require a `call_model` ancestor at all — any image-producing upstream is accepted because the cloud runner takes an explicit `image_url`. ## What gets generated When the workflow contains a camera-frame edge filter chain, the backend's `worker_codegen` adds the imports it needs (`blank_persons` + `FILTERED_FRAME_CHANNEL` for anonymize, `build_overlay_payload` + `FRAME_OVERLAY_CHANNEL` for annotate) and emits one block per filter inside the per-trigger hook, after the `model.predict(...)` call: ```python theme={null} from cyberwave.vision import blank_persons, build_overlay_payload from cyberwave.data import FILTERED_FRAME_CHANNEL, FRAME_OVERLAY_CHANNEL @cw.on_frame(twin_uuid="...", sensor="front") def _hook(frame, ctx): results = _model_yolov8n.predict(frame, confidence=0.4, twin_uuid="...") # anonymize: substitute pixels (gated on frame_filter_enabled) _frame = blank_persons(frame, results.detections, labels=['person'], mode='pixelate') cw.data.publish(FILTERED_FRAME_CHANNEL, _frame, twin_uuid="...") # annotate: publish overlay metadata (always composited) cw.data.publish( FRAME_OVERLAY_CHANNEL, build_overlay_payload(results.detections, line_width=2, font_size=14), twin_uuid="...", ) ``` `anonymize` mutates `_frame` and publishes once on `FILTERED_FRAME_CHANNEL`. `annotate` does **not** touch `_frame` — it only publishes a JSON overlay spec on `FRAME_OVERLAY_CHANNEL`, which the camera driver composites onto every frame at WebRTC encode time, regardless of the privacy flag. If the chain has zero edge-filter nodes, neither the imports nor the publishes are emitted. The vision helpers are imported lazily so workflows that don't use an edge-filter node don't pull in OpenCV. ## Frame-filter wire contract The published frame ends up on the worker container's `cyberwave.data.FILTERED_FRAME_CHANNEL` (`"frames/filtered"`). The camera driver subscribes to this channel and substitutes the frame into the WebRTC stream it serves to the frontend, provided two preconditions hold: 1. The driver's `CYBERWAVE_METADATA_FRAME_FILTER_ENABLED` flag is `true` for the twin. 2. The published frame matches the raw frame's `shape` and `dtype` (the helpers preserve both by default — don't downscale or convert colour space). If the worker stops publishing, or publishes a stale frame older than the driver's freshness window (\~200 ms), the driver emits a black frame so privacy never silently regresses. The anonymize node's [`fallback` parameter](#on-empty-detections-fallback) decides what the worker emits *before* the driver's freshness check kicks in (the worker-side gate fires every frame; the driver-side gate fires only when the worker stops publishing). See the [Frame substitution driver page](/feature-reference/edge/drivers/frame-filters) for the substitution mechanics on the driver side, and the [Edge Workers overview](./overview) for the worker container lifecycle. ## Interaction with the driver-side detection overlay The Python camera driver has a **separate, always-on detection-overlay path** that subscribes to `cw//data/detections/**` and paints hardcoded green bounding boxes onto every frame *after* any frame-filter substitution. See the [Camera detection overlays](/feature-reference/edge/drivers/camera-detection-overlays) page for that mechanism. When an `annotate` node is configured, the driver prefers its styled overlay (from `FRAME_OVERLAY_CHANNEL`) over the raw-detections fallback, so you get the colours / line widths / font size you set in the workflow editor instead of the driver's default green boxes. The fallback path stays available for twins with no `annotate` node at all. If you'd rather suppress the driver-side fallback entirely (e.g. you want clean unannotated frames whenever the workflow is paused): ```bash theme={null} # On the camera-driver host (or in the driver container env): CYBERWAVE_DETECTION_OVERLAYS=false ``` The C++ OBSBOT driver always draws its own overlays and does not subscribe to `FILTERED_FRAME_CHANNEL` or `FRAME_OVERLAY_CHANNEL`, so the edge frame-filter chain is currently a Python-driver-only surface. ## Migration from hand-written workers If you previously dropped a hand-written `~/.cyberwave/workers/my_anon_workflow.py` to do this, you can now: 1. Open the workflow editor in the UI. 2. Build `Camera Frame trigger → Call Model (your YOLO model) → Anonymize`. 3. Save and activate the workflow — the backend syncs the generated `wf_.py` to the worker. 4. Delete the hand-written file. The hotfix workarounds you may have inlined (`runtime='onnxruntime'`, custom `_pixelate_persons`, manual `_bus_for(twin_uuid)`) are no longer needed against a worker container built on top of the current SDK — the codegen output uses the helpers directly. # Model cache Source: https://docs.cyberwave.com/feature-reference/workflows/workers/model-cache How Edge Core caches ML model weights before a worker starts, including the fallback that lets Ultralytics .pt entries download themselves. ## What it does Every workflow worker that calls `cw.models.load("")` needs the weight file on disk before the worker container starts. Edge Core's **Model Manager** resolves each ID into the local cache at `~/.cyberwave/models/{model_id}/` and serves it read-only into the worker. Sources are tried in priority order; the first one that yields a checksum-verified file wins. ## Resolution order For each required model: 1. **Pre-staged on disk.** A file already at `~/.cyberwave/models/{model_id}/` is registered as `downloaded_from: prestaged` and short-circuits the catalog entirely. Use this for air-gapped sites. 2. **Cyberwave-hosted signed URL** (`GET /api/v1/mlmodels/{uuid}/weights`). Authenticated artefact in our private GCS bucket — preferred when we have mirrored the checkpoint. 3. **Upstream weights URL** (`download_url` / `metadata.upstream_weights_url`). Public community mirror — used for ONNX models we publish to `static.cyberwave.com/ml_models/`. 4. **Runtime-managed download** (new): when the catalog entry has no URL of any kind but its `edge_runtime` ships its own weight resolver (today: `ultralytics` against its GitHub releases hub), Edge Core invokes that resolver in a subprocess and caches the result as `downloaded_from: runtime_managed`. This is what lets `.pt` catalog entries (YOLO26, YOLOE-26) work without a mirrored upstream URL. Bit-rot detection (SHA-256) runs on every `ensure_model` call. Pre-staged files are never auto-overwritten by catalog updates. ## ML runtime extras The default install keeps the runtime surface lean — no Torch, no Ultralytics, no ONNX. Catalog entries that rely on the **runtime-managed download** fallback need the matching runtime installed on the edge host: ```bash theme={null} # Pull in Ultralytics so YOLO / YOLOE .pt entries can self-download pip install 'cyberwave-edge-core[ml]' # Other available extras (mirror the cyberwave SDK extras 1:1): pip install 'cyberwave-edge-core[ml-onnx]' # onnxruntime pip install 'cyberwave-edge-core[ml-tflite]' # tflite-runtime pip install 'cyberwave-edge-core[ml-stt]' # whisper.cpp catalog models only pip install 'cyberwave-edge-core[ml-stt-faster]' # faster-whisper catalog models only pip install 'cyberwave-edge-core[ml-all-audio]' # all speech extras (avoid on Pi) pip install 'cyberwave-edge-core[ml-all]' # CI/dev fat bundle only ``` Voice workflow nodes (Audio Assistant, Wake Word, Fuzzy Matcher) use separate extras — see [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies). When the required runtime is missing, the resolver raises a `RuntimeError` listing three workarounds: drop the file under `~/.cyberwave/models/{model_id}/`, upload to `/api/v1/mlmodels/{uuid}/weights`, or set `metadata.download_url` on the catalog entry. ## Pre-staging weights (air-gapped sites) ```bash theme={null} mkdir -p ~/.cyberwave/models/yoloe-26s-seg cp /usb-stick/yoloe-26s-seg.pt ~/.cyberwave/models/yoloe-26s-seg/ ``` Edge Core picks up the file on the next sync, infers the runtime from the extension (`.pt` → `ultralytics`, `.onnx` → `onnxruntime`, …), and writes a sidecar `metadata.json` so subsequent runs are deterministic. ## Self-healing the cache A failed download leaves an empty `cache_dir/{model_id}/` behind — `mkdir` runs before the network fetch, and any error in the downloader skips the cleanup. Left alone, the SDK in the worker container would later route that directory into `torch.load` and crash with `IsADirectoryError` on every restart. Edge Core handles this in three layers: * **Per-download cleanup** (conservative). A failed `_download_model` / `_download_runtime_managed` removes the staging directory before the exception propagates, provided it contains only an `.dl_*.part` partial download, a `metadata.json` sidecar, or nothing at all. Operator-staged content blocks the prune. * **Startup sweep** (conservative). `ModelManager()` walks `cache_dir/` once at construction time and prunes any per-model subdirectory that is not in the manifest *and* contains only orphan cruft. This is what unsticks hosts that were already wedged before this code shipped. Operator-staged content blocks the prune. * **`evict_model('foo')`** (decisive). When there is no manifest entry but `cache_dir/foo/` exists on disk, the directory is removed **unconditionally**. This is the recovery hook for a remote eviction API to call without shell access to the host; an explicit `evict` is treated as a stronger operator-intent signal than the conservative auto-sweeps. The SDK has matching logic in `ModelManager._resolve_model_path` so an orphan dir that survives Edge Core (e.g., on a host that hasn't picked up this release yet but mounts a fixed SDK) is also recovered inside the worker container. The Ultralytics runtime is the defensive backstop: if a directory ever reaches it (a hand-built `UltralyticsRuntime().load(...)` call bypassing the manager), it raises a clear `FileNotFoundError` instead of letting Ultralytics call `torch.load()`. ## Sidecar fields Every cached weight has a `metadata.json` next to it. Fields you'll see: | Field | Meaning | | ----------------- | --------------------------------------------------------------------------------------------------------------------- | | `downloaded_from` | `artifact_url`, `download_url`, `runtime_managed`, or `prestaged` | | `source_url` | Public URL we fetched (or `null` for `artifact_url` and `runtime_managed` — neither is a re-fetchable persistent URL) | | `upstream_url` | Provenance hint | | `checksum_sha256` | SHA-256 of the on-disk bytes; re-verified on every load | | `runtime` | `ultralytics`, `onnxruntime`, `tflite`, `tensorrt`, `torch`, `opencv` | See the full module docstring in [`cyberwave-edge-core/cyberwave_edge_core/model_manager.py`](https://github.com/cyberwave-os/cyberwave-edge-core/blob/main/cyberwave_edge_core/model_manager.py). # Run models on the edge Source: https://docs.cyberwave.com/feature-reference/workflows/workers/overview Manage, author, and deploy Python worker modules that run on-device for ML inference and event-driven processing. ## Overview Edge workers are Python modules that run inside the `cyberwaveos/edge-ml-worker` Docker container on the edge device. They use the Cyberwave SDK hook API (`@cw.on_frame`, `cw.models.load`, `cw.publish_event`) to subscribe to sensor data and emit events. There are two kinds of workers: | Kind | Filename prefix | Managed by | | ------------- | --------------------- | -------------------------------------------- | | **Custom** | anything except `wf_` | You — add/edit freely | | **Generated** | `wf_.py` | Backend workflow sync — do not edit directly | Worker files live in `{CONFIG_DIR}/workers/` (default `~/.cyberwave/workers/`). *** ## Container Image The worker container image (`cyberwaveos/edge-ml-worker`) is pulled automatically by Edge Core on first startup, in the background. This keeps `cyberwave edge install` fast and non-blocking — there is no need to wait for the image download during installation. Edge-core manages the container lifecycle — you don't need to run it manually. The container mounts worker scripts and model weights from the host as read-only volumes. | Tag | Description | | ------------ | ---------------------------- | | `latest` | Stable CPU release | | `dev` | Development CPU build | | `latest-gpu` | Stable with NVIDIA CUDA | | `dev-gpu` | Development with NVIDIA CUDA | *** ## CLI: Managing Worker Files ```bash theme={null} cyberwave worker list # list installed workers (shows origin) cyberwave worker add detect_people.py # copy a file into the workers dir cyberwave worker remove detect_people # remove a worker (with or without .py) cyberwave worker status # show worker files + container state cyberwave worker logs # stream worker container logs cyberwave worker monitor # live resource/throughput dashboard cyberwave worker doctor # diagnose silent failure modes ``` `cyberwave worker list` shows the **origin** of each worker: ``` Installed Workers (~/.cyberwave/workers) ┌───────────────────────────┬──────────┬────────────────────────────┬───────┐ │ Name │ Origin │ File │ Size │ ├───────────────────────────┼──────────┼────────────────────────────┼───────┤ │ detect_people │ custom │ detect_people.py │ 512 B │ │ wf_a1b2c3d4 │ workflow │ wf_a1b2c3d4.py │ 1.2 kB│ └───────────────────────────┴──────────┴────────────────────────────┴───────┘ ``` After adding or removing a worker file, restart the worker container so the change takes effect: ```bash theme={null} cyberwave-edge-core worker restart ``` *** ## Tuning Log Verbosity Worker containers and edge-driver containers have separate log-level knobs so you can raise one to `DEBUG` without drowning in the other. | Variable | Applies to | Default | Notes | | ---------------------------- | ------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `CYBERWAVE_WORKER_LOG_LEVEL` | Worker container only | `INFO` | Wins over `CYBERWAVE_EDGE_LOG_LEVEL` when set. Raise to `DEBUG` to surface per-frame workflow trace lines (one per node per tick). | | `CYBERWAVE_EDGE_LOG_LEVEL` | Edge drivers + worker fallback | `INFO` | Read by drivers and by the worker when `CYBERWAVE_WORKER_LOG_LEVEL` is unset. | Edge-core auto-forwards any `CYBERWAVE_*` env var it sees in its own process environment into each worker container at `docker run` time, so the same knob works whether you set it in the systemd unit, the CLI install env, or the shell. Workers print one INFO line at startup naming the resolved level and the variable that supplied it (e.g. `Worker runtime starting with log level=INFO (source=default)`), so you can verify the knob took effect without inspecting the container. In steady state, per-node workflow trace lines (`Workflow node started: `, `Workflow node finished: `) log at `DEBUG`, not `INFO` — they fire 20–30×/s on frame-driven workers and would otherwise dominate the log. Errors (`Workflow node failed`) and per-execution boundaries (`Workflow execution finished`) stay visible at the default level. The generated workflow logger is hierarchical (`cyberwave.workflows.`), so you can also tune workflow verbosity per-instance from inside a worker without touching the root logger: ```python theme={null} import logging logging.getLogger("cyberwave.workflows").setLevel(logging.WARNING) ``` *** ## CLI: Monitoring Workers `cyberwave worker monitor` opens a live-updating terminal dashboard for the running worker container. ```bash theme={null} cyberwave worker monitor # default 2s refresh cyberwave worker monitor --update 1 # 1s refresh cyberwave worker monitor -c # explicit container ``` The dashboard shows: | Section | Metrics | Source | | -------------------- | -------------------------------- | ----------------------------- | | **Resource Usage** | CPU %, memory, network I/O, PIDs | `docker stats` | | **GPU** | Utilization, memory, temperature | `nvidia-smi` (Linux only) | | **Zenoh Throughput** | Per-channel msgs/s, totals | SDK instrumentation via Zenoh | | **Worker Hooks** | Per-hook frame count, drop rate | SDK instrumentation via Zenoh | | **Model Inference** | Avg / P95 / P99 latency, count | SDK instrumentation via Zenoh | **Requirements:** * Docker must be running on the host. * For Zenoh throughput, hooks, and model metrics: `eclipse-zenoh` must be installed (`pip install eclipse-zenoh`). * GPU metrics require NVIDIA drivers and `nvidia-smi` on Linux. macOS shows "N/A" for GPU. *** ## CLI: Managing Workflows The `cyberwave workflow` command group lets you manage workflows from the terminal: ```bash theme={null} cyberwave workflow list # list workflows with status and target twin(s) cyberwave workflow list --json # JSON output cyberwave workflow show # interactive selection, shows nodes and twins cyberwave workflow show # show specific workflow cyberwave workflow create -n "Name" # create a workflow cyberwave workflow create --template motion-detection cyberwave workflow activate # activate (interactive selector) cyberwave workflow deactivate # deactivate (interactive selector) cyberwave workflow sync # sync workflow to edge device(s) via MQTT cyberwave workflow sync --edge-active # restrict selector to active edge workflows cyberwave workflow sync # sync specific workflow cyberwave workflow delete --yes # delete (skip confirmation) ``` All subcommands accept `--base-url` / `-u` to override the API URL (e.g. `http://192.168.10.101:8000`). When a UUID is omitted, an interactive arrow-key selector is shown. The `sync` command reads the workflow's `camera_frame` trigger nodes to discover which twin(s) it targets, then sends a `sync_workflows` MQTT command to each twin's edge node, which triggers an immediate HTTP pull of the latest worker files. *** ## Workflow-Generated Workers When a workflow with a **Camera Frame** trigger and a connected **Call Model** node is activated in the UI, the backend generates a `wf_*.py` worker module for that workflow. The edge node pulls these generated files during boot and on a periodic sync (default every \~5 minutes). The file is written atomically — content-identical files are left untouched to avoid spurious worker container restarts. **Scope of the pull:** Edge Core only pulls `wf_*.py` files for the twins the operator selected at install time (the `twin_uuids` list in `~/.cyberwave/environment.json`). Workflows targeting twins that are *not* in that list stay off this edge even if those twins happen to share its fingerprint in metadata — re-run `cyberwave edge install` to change the selection. **Lifecycle:** 1. Activate a workflow in the UI (trigger: Camera Frame → Call Model → edge-compatible model). 2. Edge Core syncs on next boot, `CYBERWAVE_WORKER_SYNC_INTERVAL_LOOPS` expiry, or immediately when a `sync_workflows` MQTT command arrives on the twin's command topic. That command is sent by `cyberwave workflow sync`, by `POST /twins/{uuid}/sync-workflows`, and — for `run_on_edge` workflows — automatically by the activate API itself, so flipping the UI toggle takes effect on the edge within seconds instead of up to one sync interval. 3. `wf_.py` appears in the workers directory. 4. The WorkerWatcher detects the new file and restarts the worker container. 5. The worker container loads the new module and activates the hook. **Deactivating, soft-deleting, or flipping `run_on_edge` off** publishes a surgical `remove_workflow_worker` MQTT command to each affected twin command topic, naming the specific worker file(s) to unlink. Edge Core deletes the matching `wf_*.py` and immediately reconciles the worker container lifecycle — the workflow stops running on the device within seconds rather than waiting up to one full periodic interval (\~5 minutes) plus the bulk-sync two-strikes cleanup. The same path is used for the cascade cases (workspace or environment deletion that removes the workflow). The periodic reconcile remains the correctness backstop if the MQTT publish is dropped. *** ## Raising alerts from detections `call_model` no longer publishes alerts on its own (the legacy `emit_event` config was removed). To raise alerts from a `camera_frame → call_model` chain, wire an explicit `send_alert` node downstream. Optional gating nodes preserve the previous `emit_mode` / cooldown semantics: * **`detection_event_gate`** — class filtering plus `on_enter` (new classes only) / `on_change` (count changes) modes. * **`timed_condition`** (`mode: debounce`, `cooldown_s: `) — minimum delay between consecutive fires, replacing the old `cooldown_seconds`. A typical edge chain compiles to a worker that calls `cw.publish_alert(...)` only when the gate + timer agree: ``` camera_frame → call_model → detection_event_gate → timed_condition → send_alert ``` `send_alert` whose immediate upstream is `call_model` defaults to `force=True` — the per-frame publish loop bypasses the backend's content-hash dedupe so two consecutive identical detections still raise distinct alerts. Set `parameters.force` to `false` on the `send_alert` node to opt back into the dedupe; when a gate or `timed_condition` sits between `call_model` and `send_alert` the heuristic backs off and the long-standing `force=False` default applies (the gate already debounces). A `timed_condition` placed downstream of `call_model` *without* a trailing `send_alert` is inert — the legacy implicit-alert path it used to gate is gone. The compiler attaches a warning to the resulting compilation so the silent-skip case is visible in `cyberwave workflow sync` preflight output, but the worker still ships and runs inference; nothing is published until you wire the `send_alert`. See the [`emit_event` migration table](/feature-reference/workflows#migrating-from-emit_event) for the field-by-field mapping (including the `force=True` default). *** ## Eject Pattern A generated `wf_*.py` worker can be **ejected** into a custom worker when you need to customise the logic beyond what the workflow graph supports. ```bash theme={null} # 1. Copy the generated worker to a new custom name cp ~/.cyberwave/workers/wf_a1b2c3d4.py \ ~/.cyberwave/workers/my_detector.py # 2. Edit the new custom worker nano ~/.cyberwave/workers/my_detector.py # 3. Deactivate the originating workflow in the UI # (this removes wf_a1b2c3d4.py on the next sync) ``` **Ownership after ejection:** * The `wf_*.py` file is **deleted** on the next edge sync (because the workflow was deactivated). * Your `my_detector.py` is **untouched** by edge sync — you own it. * Edge sync never writes to files that do not start with `wf_`. **Important:** do not edit `wf_*.py` files directly — they will be overwritten on the next sync. Always eject first. *** ## Writing a Custom Worker ```python theme={null} # ~/.cyberwave/workers/detect_people.py # ``cw`` is injected by the worker runtime — no import needed. # For IDE support, uncomment: from cyberwave import Cyberwave; cw: Cyberwave model = cw.models.load("yolov8n") # cached, safe to call at module level twin_uuid = cw.config.twin_uuid @cw.on_frame(twin_uuid, sensor="front") def on_frame(frame, ctx): results = model.predict(frame, classes=["person"], confidence=0.5) for det in results: cw.publish_event(twin_uuid, "person_detected", { "confidence": getattr(det, "score", None), "frame_ts": ctx.timestamp, }) ``` See the [Edge Workers SDK reference](/feature-reference/edge/drivers/edge-workers) for the full hook API. *** ## Generated Worker Format For reference, here is what a generated worker looks like (with `on_enter` emit mode and cooldown): ```python theme={null} """ Generated edge worker for workflow: Alert on Person Workflow UUID: a1b2c3d4-... Auto-generated by WorkerCodegen — DO NOT EDIT. To customise this worker, eject it: cp wf_a1b2c3d4.py alert_on_person.py """ import time # ``cw`` is injected by the worker runtime — no import needed. # For IDE support, uncomment: from cyberwave import Cyberwave; cw: Cyberwave yolov8n = cw.models.load("yolov8n.pt") # type: ignore[name-defined] # noqa: F821 _last_emit_ts_0 = 0.0 _prev_labels_0 = set() @cw.on_frame("twin-uuid", sensor="front", fps=5) # type: ignore[name-defined] # noqa: F821 def on_frame_a1b2c3d4_0(frame, ctx): """Camera frame handler for workflow 'Alert on Person'.""" global _last_emit_ts_0, _prev_labels_0 results = yolov8n.predict(frame, classes=["person"], confidence=0.5) current_labels = { getattr(d, 'label', getattr(d, 'class_name', '')) for d in results } new_labels = current_labels - _prev_labels_0 if not new_labels: _prev_labels_0 = current_labels return now = time.monotonic() if now - _last_emit_ts_0 < 5.0: return _prev_labels_0 = current_labels _last_emit_ts_0 = now for det in results: label = getattr(det, 'label', getattr(det, 'class_name', '')) if label not in new_labels: continue cw.publish_event( # type: ignore[name-defined] # noqa: F821 "twin-uuid", "person_detected", { "severity": "WARNING", "model": "yolov8n.pt", "confidence": getattr(det, 'score', None), "frame_ts": ctx.timestamp, }, ) ``` Generated workers follow the same contract as handwritten workers: `cw` is injected as a builtin, models are loaded at module level, and events are published with `cw.publish_event`. The `fps` parameter on the `@cw.on_frame` decorator controls the frame sampling rate. *** ## Troubleshooting: `@cw.on_frame` hook never fires Run `cyberwave worker doctor` first. It runs both static ("paperwork") and runtime ("actual traffic") checks. **Static checks** surface the most common config-level failures: 1. **`cyberwave-edge-core` not installed.** Worker containers are managed by edge-core. Install with `cyberwave edge install`. 2. **Worker files not world-readable.** The container runs as a non-root user (UID 1001) and cannot read mode `0600` files. `cyberwave worker add` chmods files to `0644` automatically; files installed manually may need `chmod 0644 ~/.cyberwave/workers/*.py`. 3. **No co-located driver container.** Workers only receive frames from drivers on the same Zenoh session. Check `docker ps --filter name=cyberwave-driver-` on the edge host. 4. **Env drift between driver and worker.** Mismatched `CYBERWAVE_ENVIRONMENT`, `ZENOH_CONNECT`, `CYBERWAVE_DATA_BACKEND`, or `ZENOH_SHARED_MEMORY` produces a container that looks healthy but never publishes on the key the worker subscribes to. The doctor compares these across the running driver and worker containers, and flags legacy env-var spellings (e.g. `ZENOH_SHM_ENABLED`) that are silently ignored. **Runtime checks** open a short Zenoh subscription (default 3 s) and compare the actual traffic against the key-expressions your worker hooks declare: * **`zenoh-liveness`** — counts keys seen on the bus during the probe. Zero traffic means either no publisher is running or the doctor can't reach the router. * **`keyexpr-alignment`** — for every `@cw.on_*()` hook the scanner can resolve statically, asserts at least one matching key is being put on the bus. Diagnoses three common failure modes: * **Sensor mismatch** — hook listens on `sensor="default"` but the driver publishes on `sensor="color_camera"` (or vice-versa). * **Wrong twin** — the channel is flowing, but under a different twin UUID than the hook expects. * **No publisher** — nothing on the bus looks anything like the hook's expected key. * **`keyexpr-scoping`** — flags publishers that put to non-canonical keys like `frames/color_camera` (no `cw//...` prefix). Twin-scoped hooks silently drop these. The checker accepts only the canonical shape `cw//data/[/]`. Skip the runtime probe with `--no-runtime` (pure paperwork) or extend the window with `--window 6` when traffic is bursty. The probe requires `eclipse-zenoh` on the host (`pip install --user eclipse-zenoh`); when it's missing the runtime section degrades to an info message rather than failing. A healthy edge node shows `keyexpr-alignment ok` and \~25 fps on `cw//data/frames/` in the `zenoh-liveness` top-keys list, alongside a ticking `cw/_monitor/worker_stats` key. ### Manual fallback: inspect the bus with eclipse-zenoh If the doctor can't reach the router (remote edge, unusual network) the same sanity check is one script away: ```python theme={null} import time, zenoh cfg = zenoh.Config() cfg.insert_json5("connect/endpoints", '["tcp/:7447"]') session = zenoh.open(cfg) seen = {} def on(sample): seen[str(sample.key_expr)] = seen.get(str(sample.key_expr), 0) + 1 sub = session.declare_subscriber("**", on) time.sleep(3) for k, n in sorted(seen.items(), key=lambda kv: -kv[1]): print(f"{n:>6} {k}") ``` You should see canonical keys shaped like `cw//data/frames/`. If the key list is empty or uses a different twin/sensor than your `@cw.on_frame(...)` call, fix the publisher — the worker will never see those messages otherwise. # Cameras Source: https://docs.cyberwave.com/overview/cameras Build security and video understanding automations using off-the-shelf cameras and Cyberwave Cyberwave treats every camera the same (**USB webcams, IP cameras, depth cameras, infrared, industrial GigE**): drop a digital twin into an [environment](/feature-reference/architecture/key-concepts#environment), pair the hardware, and start consuming the stream from the dashboard, the [Python SDK](/overview/tools/python-sdk), or a [Workflow](/feature-reference/workflows).