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.

Browser operator / AJAX PsyProbe HTTP server static: html web root /robot/... (aliases) /api/query /api/getcomponentdata standard tabs + custom tabs (elements/*.html templates) Nodes & components stats, activity, logs RequestStore Catalog latest messages by name Private data setPrivateData + mimetype HTTP live view /api/query /api/getcomponentdata
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 / childMeaningDefault
locationWeb root directory for PsyProbe (overrides the auto-detected html dir and the html= cmdline)built-in autodetect
portAdds a dedicated PsyProbe HTTP interface on this portshares main port
defaultportno removes PsyProbe from the main porton 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 attributeMeaning
nameRequest name used in the query URL (required)
triggerSource trigger feeding this store (required)
keyA 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
keytypeReserved; not currently used Stub
datatyperaw = raw pixels; the message must contain width/height and a valid bitmap is built
mimetypeRequired; standard (application/json, text/html, text/xml) or short forms json/xml/text
maxkeepHistory count (default 1)
maxfrequencyMax 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.
Psyclone AIOS · CMLabs