BotDeviceMessage bot.device-message@1

Generated at from openvibe-contracts v0.97.0 and openvibe-sdk v0.26.0.

Version
1.0.0
Owner
bot
Visibility
first-party
Status
active
Compatibility
backward
Decision
ADR-043
Schema
https://openvibe.network/contracts/bot/device-message.v1.json

bot.device-message@1 (ADR-043 decision 5): one frame on OpenVibe.Bot's device WebSocket (wss://openvibe.bot/device), JSON with v, seq and ts on every frame. Server to device: hello, config, command, estop, heartbeat_ack, error, paired (after a pair frame), rotate (a Network-paired machine is asked to rotate its credential with Network). Device to server: pair (the only frame an unauthenticated socket may send), status, telemetry, ack, nack, heartbeat, reauth (Network-paired machines), estop_state. The job frames on the same socket are platform.job-frame@1, not this contract. This duplicates two implementations that must not drift: OpenVibe.Bot server/realtime.js (the sender and reader in Bot) and OpenVibe.Node internal/protocol/protocol.go (the Go structs of the device agent).

Fields

This schema has no named fields.

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: command
{
  "v": 1,
  "seq": 3,
  "ts": 1759600000003,
  "type": "command",
  "id": "cmd_01J8Z4Q9V5X1Z3BD6P9S2T5W7Y",
  "ref": "op-7",
  "kind": "drive",
  "value": {
    "throttle": 0.5,
    "steer": 0
  },
  "deadline_ms": 1759600000300,
  "operator": {
    "subject": "usr_01J8Z4P7T3W9Y1AC5N8R0S4V6X",
    "role": "owner"
  },
  "robot_id": "rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X"
}
Valid: config
{
  "v": 1,
  "seq": 2,
  "ts": 1759600000002,
  "type": "config",
  "heartbeat_ms": 1000,
  "limits": {
    "max_speed": 0.6,
    "max_turn": 1,
    "max_command_ms": 300,
    "heartbeat_ms": 1000
  },
  "allowed_commands": [
    "drive",
    "actuator",
    "halt"
  ],
  "estop_latched": false
}
Valid: hello
{
  "v": 1,
  "seq": 1,
  "ts": 1759600000001,
  "type": "hello",
  "session_id": "ses_1",
  "device_id": "dev_01J8Z4N5S2V8X0ZB4M7Q9R3T5W",
  "robot_ids": [
    "rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X"
  ],
  "server_time": "2026-10-04T12:00:00.000Z"
}
Valid: nack
{
  "v": 1,
  "seq": 5,
  "ts": 1759600000005,
  "type": "nack",
  "id": "cmd_01J8Z4Q9V5X1Z3BD6P9S2T5W7Y",
  "fault_code": "estopped",
  "message": "the remote e-stop is latched"
}
Valid: node-status
{
  "v": 1,
  "seq": 4,
  "ts": 1759600000004,
  "type": "status",
  "firmware": "0.1.2",
  "capabilities": {
    "adeept_adr036": {
      "drive": true
    }
  },
  "agent_version": "0.1.2",
  "device_kind": "onboard",
  "os": "linux",
  "arch": "arm64",
  "drivers": [
    {
      "name": "adeept_adr036",
      "driver": "pca9685",
      "version": "0.1.2",
      "state": "running"
    }
  ],
  "faults": [],
  "estop_latched": false,
  "local_stop": false,
  "video": "whip"
}
Valid: paired-without-video
{
  "v": 1,
  "seq": 1,
  "ts": 1759600000001,
  "type": "paired",
  "device_id": "dev_01J8Z4N5S2V8X0ZB4M7Q9R3T5W",
  "credential": "example-credential-shown-once",
  "video": "not_configured",
  "robot_ids": [
    "rob_01J8Z4M2Q0R7T9YV3K6N8P1W2X"
  ],
  "profile_id": "sim.rover",
  "profile": {
    "id": "sim.rover",
    "version": 1,
    "name": "Simulated rover",
    "vendor": null,
    "kind": "server",
    "description": null,
    "capabilities": [
      "drive.differential",
      "camera"
    ],
    "variants": null,
    "mapping": {
      "driver": "sim"
    },
    "commands": {
      "drive": {
        "axes": {
          "throttle": [
            -1,
            1
          ],
          "steer": [
            -1,
            1
          ]
        }
      },
      "say": {
        "max_chars": 200
      },
      "halt": {}
    },
    "widgets": [
      {
        "type": "drive",
        "capability": "drive.differential",
        "label": "Drive",
        "order": 1,
        "command": {
          "kind": "drive"
        }
      },
      {
        "type": "camera",
        "capability": "camera",
        "order": 2
      }
    ],
    "camera": null,
    "limits": {
      "max_speed": 1,
      "max_turn": 1,
      "max_command_ms": 300,
      "heartbeat_ms": 1000
    }
  }
}
Valid: rotate
{
  "v": 1,
  "seq": 9,
  "ts": 1759600000009,
  "type": "rotate"
}
Valid: telemetry
{
  "v": 1,
  "seq": 6,
  "ts": 1759600000006,
  "type": "telemetry",
  "battery": {
    "volts": 7.6,
    "percent": 81
  },
  "sensors": {
    "distance_cm": 42
  },
  "events": [
    {
      "name": "low_battery",
      "ts": 1759600000006
    }
  ]
}
Rejected: ack-extra-field
{
  "v": 1,
  "seq": 7,
  "ts": 1759600000007,
  "type": "ack",
  "id": "cmd_1",
  "result": "ok"
}
Rejected: job-frame
{
  "v": 1,
  "seq": 8,
  "ts": 1759600000008,
  "type": "job_started",
  "id": "job_01J8Z4Q9V5X1Z3BD6P9S2T5W7Y",
  "started_ms": 1
}
Rejected: no-seq
{
  "v": 1,
  "ts": 1759600000000,
  "type": "heartbeat",
  "t": 5
}
Rejected: unknown-kind
{
  "v": 1,
  "seq": 3,
  "ts": 1759600000003,
  "type": "command",
  "id": "cmd_1",
  "kind": "fly"
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('bot.device-message@1', value);   // { valid, errors: [{ path, message }] }