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++ 샘플은 선택자를 지정하지 않고 쿼리를 수행합니다.
매개변수
| 매개변수 | 기본값 | 용도 |
|---|---|---|
| 서비스 URL | http://localhost:10001 | HTTP 기본 URL |
| 엔드포인트 | /devices | 장치 감지 엔드포인트 |
| 세션 선택기 | (없음) | ?session=:0、?session=:-1、?session=:my_profile:0、?session=co.haply.hub::*:0(glob 와일드카드 지원) — 셀렉터를 참조하십시오. Python 예제에서는 --session SELECTOR 로 공개되어 있습니다(튜토리얼 08(동일한 플래그). |
주요 코드
- 파이썬
- C++ (nlohmann)
- C++ (Glaze)
파이썬 예제에서는 세션 선택기를 --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 처리에libhvJSON 파싱에는 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/ 확인해 주십시오.