openvibers/openvibe.bot Commits

Bot: the front page lists every robot Bot has a profile for (ROS 2, LOOI and a phone joined) (#110)

OP OpenVibers committed 29 days ago · 288f8c6520 · 2 files, +12 −2

**The Bot front page lists every robot Bot ships a profile for.**

**Found:** while reviewing every home page. "Robots it drives today" named three robots: the Adeept car, Cozmo and the simulated rover. Bot also ships profiles for ROS 2 robots (Bot#95, with the Node's `plugins/ros2` driver), LOOI (10-11) and a phone, and nothing on the front page said so. Three cards also left an empty slot in a four-column row.

**Now, six cards, each worded as its profile is:**
- Adeept 4WD Smart Car (unchanged);
- **ROS 2 robots:** a TurtleBot 3 or 4, a Jackal or a home-built base on cmd_vel, and mecanum or omni bases; drive, camera, the distance ahead and the battery, through the OpenVibe Node;
- **LOOI:** drive and head tilt over Bluetooth from a computer running the Node and the community LOOI driver (credited as community-made);
- **Cozmo:** drive, head and lift, speech, its face display, lights and camera (it said only "through the device agent");
- **A phone:** a robot's eyes, voice and face from its browser, with nothing to install;
- the simulated rover (unchanged).

A lede adds that each robot's controls are drawn from its profile, and that ONVIF PTZ cameras and a generic relay come with them.

**Tests (`home.test.js`):**
- the six card titles, in order, each backed by a shipped profile file;
- the "no promise the service cannot keep" list drops `ROS 2`, which Bot#95 made true. ESP32, Android, "arrive paired", buying and webhooks stay forbidden.

The 8 px frame around this page's footer is fixed network-wide by openvibe-shared 4.1.7 (`shell.page()` resets the body margin), which reaches Bot in the next pin round.

Changes

ddiff --git a/server/web/home.js b/server/web/home.js
iindex e961cf2..887b194 100644
---- a/server/web/home.js
++++ b/server/web/home.js
@@@ -70,9 +70,14 @@ function sections({ signedIn }) {
],
}) + showcase.features({
title: 'Robots it drives today',
++ // One card per robot profile Bot ships (server/profiles): what each one drives, said as its profile says it.
++ lede: 'Each has a profile the panel draws its controls from. ONVIF PTZ cameras and a generic relay, for anything a local script can switch, come with them.',
items: [
{ icon: 'ov:check', title: 'Adeept 4WD Smart Car', text: 'The Raspberry Pi kit, with its parts list and build guide; a mecanum-wheel build has its own profile. The first robot on OpenVibe.Bot.' },
-- { icon: 'ov:check', title: 'Cozmo', text: 'Through the device agent on a computer next to it.' },
++ { icon: 'ov:check', title: 'ROS 2 robots', text: 'A TurtleBot 3 or 4, a Jackal or a home-built base on cmd_vel, mecanum and omni bases too: drive, camera, the distance ahead and the battery, through the OpenVibe Node.' },
++ { icon: 'ov:check', title: 'LOOI', text: 'The tracked desk robot with a phone for a face: drive and head tilt over Bluetooth from a computer running the OpenVibe Node and the community LOOI driver.' },
++ { icon: 'ov:check', title: 'Cozmo', text: 'Drive, head and lift, speech, its face display, lights and camera, through a computer next to it that joins the robot\'s Wi-Fi.' },
++ { icon: 'ov:check', title: 'A phone', text: 'Any phone as a robot\'s eyes, voice and face, from its browser with nothing to install: camera, speech, a full-screen face and its torch.' },
{ icon: 'ov:check', title: 'A simulated rover', text: 'A rover in a small arena with a camera, a range finder, line sensors, headlights and a horn. Drive it at /try in your browser, with no account and no hardware.' },
],
}) + `<section class="sc-sec" id="build"><h2>Build for OpenVibe.Bot</h2>
ddiff --git a/test/home.test.js b/test/home.test.js
iindex ead61d1..2f27851 100644
---- a/test/home.test.js
++++ b/test/home.test.js
@@@ -26,6 +26,10 @@ const { boot, check, done } = require('./helpers/app');
assert.match(html, /<link rel="canonical" href="http:\/\/bot\.test\/">/);
assert.match(html, /href="\/auth\/login\?next=%2Frobots">Sign in with OpenVibe/);
assert.strictEqual((html.match(/<h1[ >]/g) || []).length, 1, 'one h1');
++ // Every robot Bot ships a profile for is on the front page: six cards under "Robots it drives today".
++ const robots = (/<section class="sc-sec"[^>]*aria-labelledby="sc-robots-it-drives-today"[\s\S]*?<\/section>/.exec(html) || [''])[0];
++ assert.deepStrictEqual([...robots.matchAll(/<b>([^<]+)<\/b>/g)].map((m) => m[1]), ['Adeept 4WD Smart Car', 'ROS 2 robots', 'LOOI', 'Cozmo', 'A phone', 'A simulated rover']);
++ for (const id of ['adeept.adr036', 'ros2.diffdrive', 'looi', 'cozmo', 'phone.camera', 'sim.rover']) assert.ok(require('fs').existsSync(require('path').join(__dirname, '..', 'server', 'profiles', `${id}.json`)), `${id} is a shipped profile`);
const css = html.match(/href="(\/shared\/showcase\.css\?v=[0-9a-f]{12})"/);
assert.ok(css, 'links the showcase stylesheet');
const sheet = await get(css[1]);
@@@ -37,7 +41,8 @@ const { boot, check, done } = require('./helpers/app');
await check('GET /: no promise the service cannot keep (video waits for OpenRestream; no store, no unsupported boards)', async () => {
const html = await (await get('/')).text();
assert.match(html, /sends its camera over WebRTC to OpenRestream and the panel plays it live/);
-- for (const claim of [/ESP32/, /ROS 2/, /Android/, /arrive paired/i, /\bbuy\b/i, /webhook/i]) assert.ok(!claim.test(html), `no ${claim}`);
++ // ROS 2 left this list with Bot#95 (ros2.diffdrive, ros2.holonomic, the Node's plugins/ros2 driver).
++ for (const claim of [/ESP32/, /Android/, /arrive paired/i, /\bbuy\b/i, /webhook/i]) assert.ok(!claim.test(html), `no ${claim}`);
});
await check('GET /: signed in, the first action opens your robots', async () => {