00. 디바이스 목록
HTTP REST API를 통해 연결된 모든 Haply 디바이스를 검색합니다 — WebSocket 없이도 가능합니다. 런타임이 실행 중이며 하드웨어를 감지하고 있는지 확인하는 간단한 스모크 테스트입니다.
학습 내용:
GET /devices를 호출하여 Inverse3, VerseGrip, 무선 VerseGrip 디바이스 목록 조회하기- JSON 응답에서 디바이스 ID를 읽고 디바이스 유형별로 그룹화하기
- 세션 셀렉터를 사용하여 원시 디바이스 좌표와 세션의 애플리케이션 공간 뷰 사이를 전환하기
워크플로
GET http://localhost:10001/devices요청을 보냅니다.- JSON 응답을 파싱합니다 — 최상위 배열은 세 개입니다:
inverse3,verse_grip,wireless_verse_grip. - 디바이스 ID를 유형별로 그룹화하여 출력합니다. 배열이 비어 있으면 해당 유형의 디바이스가 감지되지 않은 것입니다.
- 세션 셀렉터를
?session=<selector>형태로 덧붙이면, 응답은 해당 세션의 디바이스로 필터링되고 좌표는 세션의 애플리케이션 공간(basis, mount, workspace 적용)으로 변환됩니다. Python 샘플은 이를--session SELECTORCLI 인수로 제공합니다(:profile:instance,#id,:-1,:0, … 허용). 이 플래그와 도움말 텍스트는 튜토리얼 08 (HTTP 원격 구성)에서 사용하는 것과 동일하므로, 여기서 찾은 셀렉터를 그대로 그곳에 붙여 넣을 수 있습니다. C++ 샘플은 셀렉터 없이 조회합니다.
매개변수
| 매개변수 | 기본값 | 용도 |
|---|---|---|
| 서비스 URL | http://localhost:10001 | HTTP 기본 URL |
| 엔드포인트 | /devices | 디바이스 검색 엔드포인트 |
| 세션 셀렉터 | (없음) | ?session=:0, ?session=:-1, ?session=:my_profile:0, ?session=co.haply.hub::*:0 (글롭 와일드카드 지원) — 셀렉터 참고. 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++ 변형은 HTTP 통신에 libhv를 사용하고 파싱에는 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());
}
튜토리얼 00도 SDK와 함께 로컬에 설치되어 있습니다 — 서비스 설치 디렉터리 아래의 tutorials/00-haply-inverse-device-list/에서 확인하십시오.