Routines, webhooks and your agent
A robot can move without anyone holding the controls, tell your own server what happened to it, and take orders from your OpenVibe.Actor agent. Every one of these goes through the same gate as a person at the panel: the robot's limits, cooldowns and e-stop apply, and the audit records each command.
Steps
Routines and the agent both speak in steps, one per line, checked against the robot's own profile. A robot takes only what it has:
forward 2,back 1 0.4,left 0.5,right 0.5: drive for that many seconds, at an optional speed (0–1);stop.wait 1: pause.say Hello,face happy,show Hi: speech, a face or text on its display.headlights #ff8800,horn A4 0.3,lights off,pan 0.5 1: an actuator or a camera axis by its name in the profile, with a value and how long to hold it.press horn: one of its buttons.
A held step (a motion or a tone) is re-sent inside the device's deadman window and released at its end. A refused step (the e-stop, the robot going offline, a cooldown) stops the rest, with the reason.
Routines
On a robot's panel, under Routines, the owner names a routine, writes its steps and picks when it runs:
- when the owner presses Run;
- every N minutes (at least 5);
- daily at a UTC time, on chosen weekdays;
- each time the robot comes online.
A routine runs as the owner. One routine runs on a robot at a time; removing a running routine stops it. Limits: 60 steps, 60 seconds a step, 10 minutes in all. The same list is GET|POST /api/v1/robots/:id/routines, POST …/routines/:rid/run and DELETE …/routines/:rid, for the owner or a service with bot.robot.manage.
Webhooks
Under Webhooks, the owner adds up to five https addresses, each for some of the robot's events: bot.robot.online, bot.robot.offline, bot.estop.set, bot.estop.cleared, bot.command.refused. Each hook has its own secret (whsec_…), shown once when it is made.
Bot posts { id, type, robot_id, occurred_at, data }, signed the way OpenVibe.Events signs a delivery (X-OpenVibe-Timestamp, X-OpenVibe-Signature-V2), only to public addresses, never following a redirect. Anything but a 2xx is retried after 30 seconds, then 2, 10, 30 and 120 minutes. Check the signature before trusting a delivery:
const { verifyDeliveryV2 } = require('openvibe-sdk/events');
// Express, with the raw body: the signature covers the exact bytes Bot sent.
app.post('/robot-events', express.text({ type: 'application/json' }), (req, res) => {
if (!verifyDeliveryV2(req.body, req.headers, process.env.ROBOT_WEBHOOK_SECRET)) return res.status(401).end();
const event = JSON.parse(req.body); // { id, type, robot_id, occurred_at, data }
if (event.type === 'bot.estop.set') console.log('robot', event.robot_id, 'stopped');
res.status(204).end();
});
The API is GET|POST /api/v1/robots/:id/webhooks (the POST answers the secret) and DELETE …/webhooks/:hid.
Your agent
On the panel, Your agent has one switch: Let my OpenVibe.Actor agent drive this robot. It is off until the owner turns it on. With it on, a task you give OpenVibe.Actor, such as "drive my rover forward for a second and turn its lights green", can see your robots (online, e-stop, battery, sensors) and run steps on this one, as you. It never acts for anyone else, and turning the switch off stops it at once.
Your own token runs steps directly, and answers when they end:
curl -X POST https://openvibe.bot/api/v1/robots/rob_…/steps \
-H "Authorization: Bearer $OPENVIBE_TOKEN" -H "Content-Type: application/json" \
-d '{"steps": "forward 1\nleft 0.5\nheadlights #00ff00\nstop"}'
# → {"robot_id": "rob_…", "result": "done", "steps": 4}
GET /api/v1/robots/:id/steps answers the robot's state and the step words it takes. A call takes at most 20 steps and 30 seconds; the agent's calls are refused with 403 bot.agent_not_allowed while the switch is off.
The Node and its bundled drivers are in OpenVibers/OpenVibe.Node; the full protocol is protocol.md and the plugin contract is plugins.md.