00. 设备列表
通过 HTTP REST API 检测所有已连接的 Haply 设备(无需 WebSocket)。这是一个简单的烟雾测试,用于确认运行时已启动且能够检测到硬件。
学习内容:
GET /devices查询以列出Inverse3、VerseGrip以及无线VerseGrip设备- 从JSON响应中读取设备ID,并按设备类型进行分组
- 使用会话选择器在原始设备坐标与会话的应用程序空间视图之间切换
工作流
GET http://localhost:10001/devices将发送。- 解析 JSON 响应。共有 3 个顶级数组:
inverse3、verse_grip、wireless_verse_grip。 - 将设备 ID 按类型分组后输出。如果数组为空,则表示未检测到该类型的设备。
- 会话选择器を
?session=<selector>如果将其作为参数添加,响应将限定为该会话中的设备,坐标也将转换为该应用程序的空间(应用basis、mount和workspace坐标系)。在Python示例中,这被实现为--session SELECTOR作为CLI参数公开(:profile:instance、#id、:-1、:0、……(接受)。这是教程08(HTTP远程设置)由于使用的标志和帮助文本与该教程中完全一致,因此您可以将在此处找到的选择器直接复制粘贴到该教程中。C++示例在查询时未指定选择器。
参数
| 参数 | 默认 | 用途 |
|---|---|---|
| 服务网址 | http://localhost:10001 | HTTP 基础 URL |
| 端点 | /devices | 设备检测端点 |
| 会话选择器 | (无) | ?session=:0、?session=:-1、?session=:my_profile:0、?session=co.haply.hub::*:0(支持glob通配符)— 选择器请参阅。在 Python 示例中, --session SELECTOR 已作为……发布(教程08(与该标志相同)。 |
主要代码
- Python
- C++ (nlohmann)
- C++ (Glaze)
在 Python 示例中,会话选择器 --session SELECTOR 作为argparse参数公开。如果未指定该参数,设备将以原始设备空间坐标返回。如果指定了该参数,则会筛选出所选会话中的设备,并将其转换为应用程序空间坐标。帮助文本为教程08(HTTP远程设置)因为与……相同,所以可以将这里找到的选择器直接复制粘贴到该教程中。
def parse_args():
parser = argparse.ArgumentParser(
description="List connected Haply Inverse devices via the HTTP API.")
parser.add_argument(
"--session", type=str, default="",
help=(
"Session selector. Formats:\n"
" :profile:instance by profile name (e.g. ':my_profile:0')\n"
" pattern:instance glob wildcard in profile (e.g. 'co.haply.hub::*:0')\n"
" '*' matches any sequence, '?' one character\n"
" #session_id by numeric id (e.g. '#42' — quote in shells to escape '#')\n"
" :-1 the last active session\n"
" :0 the first session"
))
return parser.parse_args()
def main():
args = parse_args()
session = args.session or None
url = f"{BASE_URL}/devices"
if session:
url += f"?session={session}"
print(f"Querying devices for session '{session}' (application space)\n")
else:
print("Querying all detected devices (device space)\n")
r = requests.get(url, timeout=3)
r.raise_for_status()
data = r.json()
print_devices("Inverse3", data.get("inverse3"))
print_devices("Wired Verse Grip", data.get("verse_grip"))
print_devices("Wireless Verse Grip", data.get("wireless_verse_grip"))
在 C++ Variant 中,处理 HTTP 时libhv在解析JSON时,我们使用了nlohmann/json。contains() 使用该方法手动检查各顶级键,如果数组不为空,则遍历该数组。在 C++ 示例中,会话选择器的 CLI 参数并未公开。如果需要应用程序空间的坐标,请在 URL 中添加 ?session=<selector> 请添加。
HttpResponsePtr resp = requests::get("localhost:10001/devices");
if (resp == nullptr) { /* ... error ... */ return 1; }
json data = json::parse(resp->body);
if (data.contains("inverse3") && !data["inverse3"].empty()) {
printf("Inverse3 found:\n");
for (auto &element : data["inverse3"]) {
printf(" (id: %s)\n", element["device_id"].get<std::string>().c_str());
}
}
// ... same pattern for verse_grip and wireless_verse_grip
在 Glaze 变体中,会声明一个反映 JSON 结构的简单结构体。Glaze 会使用编译时反射来设置其值。contains() 无需进行此检查。如果数组不存在,则返回空的 std::vector<> 将作为结果返回。
static constexpr glz::opts glz_settings{.error_on_unknown_keys = false};
struct device_entry { std::string device_id; };
struct devices_response {
std::vector<device_entry> inverse3;
std::vector<device_entry> verse_grip;
std::vector<device_entry> wireless_verse_grip;
};
// In main():
HttpResponsePtr resp = requests::get("localhost:10001/devices");
devices_response data;
if (auto err = glz::read<glz_settings>(data, resp->body)) {
printf("JSON parse error: %s\n", glz::format_error(err, resp->body).c_str());
return 1;
}
for (const auto &dev : data.inverse3) {
printf(" (id: %s)\n", dev.device_id.c_str());
}
随SDK安装程序一起提供
教程00也已随SDK一起安装在本地。位于服务安装目录下的 tutorials/00-haply-inverse-device-list/ 请确认。