CMLabs · Psyclone AIOS

# 3. PsyProbe Configuration

Configuring the built-in web interface: ports and web roots, custom subsites, custom tabs, private data, RequestStore catalogs and custom visualisers.

## PsyProbe architecture

PsyProbe is Psyclone's built-in HTTP interface: point any browser at the main port (`http://localhost:10000/` by default) and you get a live, self-updating view of every node, space and component. It serves static HTML/JS from a web root, and answers a small set of dynamic API endpoints backed by the running system.

PsyProbe serves the standard live views plus three extension paths: URL aliases (custom subsites), the RequestStore query API and per-component private data.

## The <psyprobe> element

    <psyprobe location="otherdir/html" port="8080" defaultport="no">
      <alias name="robot" location="/somedir/html" default="index.html" />
      <post name="TestMove" type="Robot.Command.Move.Forward" />
    </psyprobe>

Attribute / child | Meaning | Default
--- | --- | ---
`location` | Web root directory for PsyProbe (overrides the auto-detected `html` dir and the `html=` cmdline) | built-in autodetect
`port` | Adds a dedicated PsyProbe HTTP interface on this port | shares main port
`defaultport` | `no` removes PsyProbe from the main port | on main port
`<alias>` | Custom subsite: URL prefix → any local directory, optional default file | —
`<post>` | A clickable manual-test post in the PsyProbe UI (same attributes as a module-level post, including XML content) | —

Note. A known parsing quirk: with multiple `<alias>` children the loop reuses the wrong index, so in practice only the first alias is reliably read. Prefer a single alias pointing at a directory tree.

## Custom subsites

`<alias name="robot" location="/somedir/html" default="index.html" />` maps `http://host:port/robot/anydir/anyfile` to `/somedir/html/anydir/anyfile` — any local path can be published under the PsyProbe port. This is the simplest way to ship a complete custom operator UI (the CoCoMaps robots served their whole control panel this way). Alternatively, just drop files into the web-root tree and load `http://localhost:10000/mycustompage.html`.

## Creating custom tabs

Every component page in PsyProbe has standard tabs (Performance, Activity, Subscriptions, Log, Data). A component can add its own tab by pointing at an HTML element template in the web root:

    api->addPsyProbeCustomView("Stored Messages", "elements/whiteboardmessages.html");

    api.addPsyProbeCustomView("Stored Messages", "elements/whiteboardmessages.html")

A template is a plain HTML fragment with a script implementing two functions; PsyProbe instantiates it per component:

    <script>
    var TemplateCompID;    // set by PsyProbe
    var TemplateCompName;

    function loadTemplate($target, compID) {
        // called once; componentMap[compID] holds the component record
    }
    function updateTemplate($target, compID) {
        // called every update cycle; refresh the view
    }
    </script>

The bundled `elements/` directory of the web root is the reference library: `elements/whiteboardmessages.html` (the Whiteboard's own Stored Messages tab) is the canonical example to copy, and the other `elements/*.html` templates show the same pattern for performance panes, dataflow views and hierarchical diagrams. Custom tabs can also be declared in the spec with a `<customview name=".." template="..">` child on the component.

## Working with private data

Any component can publish binary or textual blobs as private data; give it a mimetype and it appears in the component's Data tab and becomes fetchable over HTTP:

    // component side
    api->setPrivateData("My Data", str.c_str(), str.length(), "application/json");

    // browser / AJAX side
    GET /api/getcomponentdata?compid=15&name=My%20Data&format=json

    # component side
    api.setPrivateData("My Data", str, "application/json")

    # browser / AJAX side
    GET /api/getcomponentdata?compid=15&name=My%20Data&format=json

Supported formats on the GET are `text`, `xml`, `json`, `html` and `binary` (e.g. `image/bmp` data renders as an image). You need the component ID, the entry name and the stored format. This is extension path number two: a custom page polling `getcomponentdata` can visualise anything a module chooses to expose.

## RequestStore: serving live messages over HTTP

The RequestStore catalog subscribes to messages system-wide, keeps the most recent, and serves parts or whole messages via the web API — the standard way to feed custom dashboards without writing any C++ on the web side:

    <catalog name="RequestStore" type="RequestStore">
      <trigger name="VideoFrame" type="robot.sensor.video" />
      <trigger name="Status" type="Robot.Status" />
      <setup>
        <store name="VideoFrame" trigger="VideoFrame" datatype="raw" mimetype="image/bmp" />
        <store name="Status" trigger="Status" mimetype="application/json" maxkeep="1" />
        <store name="StatusTime" trigger="Status" key="timetext" mimetype="text" />
      </setup>
    </catalog>

    GET /api/query?from=RequestStore&query=VideoFrame
    GET /api/query?from=RequestStore&query=Status

Store attribute | Meaning
--- | ---
`name` | Request name used in the query URL (required)
`trigger` | Source trigger feeding this store (required)
`key` | A user entry, or header fields `time` (µs since year 0), `timetext`, `type`, `size`, `content`; omitted ⇒ whole message rendered as JSON/XML/HTML/TEXT per mimetype
`keytype` | Reserved; not currently used Stub
`datatype` | `raw` = raw pixels; the message must contain width/height and a valid bitmap is built
`mimetype` | Required; standard (`application/json`, `text/html`, `text/xml`) or short forms `json`/`xml`/`text`
`maxkeep` | History count (default 1)
`maxfrequency` | Max messages kept per second (rate limit)

## Custom visualisers: putting it together

The four extension paths, in increasing effort:

- Custom subsite / plain page — static HTML in the web root or an alias; fetches data with AJAX.
- RequestStore — declare stores in the spec; the page polls `/api/query`. No native code.
- Private data — the module computes exactly what to show (JSON, bitmap…) and publishes it; the page polls `/api/getcomponentdata`.
- Custom tab — an element template registered via `addPsyProbeCustomView` or `<customview>`; integrates into PsyProbe's own component pages and update cycle.

Tip. For dashboards that must survive PsyProbe restarts and be shareable, prefer a RequestStore + subsite combination: everything is declared in the PsySpec and plain HTML — nothing to recompile.
PreviousSystem Messages NextCustom Interfaces