# Path: robel/components/tracking/virtual_reality/device.py
# class VrDevice:
#     """Represents an OpenVR device."""
# 
#     def __init__(self, vr_system, index: int):
#         """Initializes a new VrDevice with the given device index."""
#         self._vr_system = vr_system
#         self._index = index
#         self._value_cache = {}
# 
#     @property
#     def index(self) -> int:
#         """Returns the device index."""
#         return self._index
# 
#     def is_connected(self) -> bool:
#         """Returns whether the device is connected."""
#         return self._vr_system.isTrackedDeviceConnected(self._index)
# 
#     def get_serial(self) -> str:
#         """Returns the serial number of the device."""
#         return self._get_string(openvr.Prop_SerialNumber_String)
# 
#     def get_model(self) -> str:
#         """Returns the model number of the device."""
#         return self._get_string(openvr.Prop_ModelNumber_String)
# 
#     def get_model_name(self) -> str:
#         """Returns the model name of the device."""
#         return self._get_string(openvr.Prop_RenderModelName_String)
# 
#     def get_summary(self) -> str:
#         """Returns a summary of information about the device."""
#         connected = self.is_connected()
#         info = '[{} - {}]'.format(self._index,
#                                   'Connected' if connected else 'Disconnected')
#         if connected:
#             info += ' {} ({})'.format(self.get_model_name(), self.get_serial())
#         return info
# 
#     def _get_string(self, prop_type) -> str:
#         """Returns a string property of the device."""
#         if prop_type in self._value_cache:
#             return self._value_cache[prop_type]
#         value = self._vr_system.getStringTrackedDeviceProperty(
#             self._index, prop_type).decode('utf-8')
#         self._value_cache[prop_type] = value
#         return value
# 
#     def _get_bool(self, prop_type) -> bool:
#         """Returns a boolean property of the device."""
#         if prop_type in self._value_cache:
#             return self._value_cache[prop_type]
#         value = self._vr_system.getBoolTrackedDeviceProperty(
#             self._index, prop_type)[0]
#         self._value_cache[prop_type] = value
#         return value
# 
#     def _get_float(self, prop_type) -> float:
#         """Returns a float property of the device."""
#         if prop_type in self._value_cache:
#             return self._value_cache[prop_type]
#         value = self._vr_system.getFloatTrackedDeviceProperty(
#             self._index, prop_type)[0]
#         self._value_cache[prop_type] = value
#         return value
# 
# Path: robel/components/tracking/virtual_reality/poses.py
# class VrPoseBatch:
#     """Represents a batch of poses calculated by the OpenVR system."""
# 
#     def __init__(self, vr_system, time_from_now: float = 0.0):
#         """Initializes a new pose batch."""
#         self._vr_system = vr_system
#         # Query poses for all devices.
#         self.poses = self._vr_system.getDeviceToAbsoluteTrackingPose(
#             openvr.TrackingUniverseStanding, time_from_now,
#             openvr.k_unMaxTrackedDeviceCount)
# 
#     def get_state(self, device: VrDevice) -> TrackerState:
#         """Returns the tracking state for the given device."""
#         if not self.poses[device.index].bPoseIsValid:
#             state = TrackerState()
#         else:
#             vr_pose = np.ctypeslib.as_array(
#                 self.poses[device.index].mDeviceToAbsoluteTracking[:],
#                 shape=(3, 4))
#             # Check that the pose is valid.
#             # If all of the translations are 0, get from the cache.
#             assert vr_pose.shape == (3, 4)
#             state = TrackerState(pos=vr_pose[:, 3], rot=vr_pose[:, :3])
#         return state


from typing import List, Union
from robel.components.tracking.virtual_reality.device import VrDevice
from robel.components.tracking.virtual_reality.poses import VrPoseBatch
import openvr
                'Could not find device with name or index: {} (Available: {})'
                .format(identifier, sorted(self._device_serial_lookup.keys())))

        if identifier in self._device_index_lookup:
            return self._device_index_lookup[identifier]
        return self._device_serial_lookup[identifier]

    def discover_devices(self) -> List[VrDevice]:
        """Returns and caches all connected devices."""
        self._device_index_lookup.clear()
        self._device_serial_lookup.clear()
        devices = []
        for device_index in range(openvr.k_unMaxTrackedDeviceCount):
            device = VrDevice(self._vr_system, device_index)
            if not device.is_connected():
                continue
            devices.append(device)
            self._device_index_lookup[str(device.index)] = device
            self._device_serial_lookup[device.get_serial()] = device
        self._devices = devices
        return devices

    def get_poses(self, time_from_now: float = 0.0,
                  update_plot: bool = True) -> VrPoseBatch:
        """Returns a batch of poses that can be queried per device.

        Args:
            time_from_now: The seconds into the future to read poses.
            update_plot: If True, updates an existing plot.
        """

# Path: robel/components/tracking/virtual_reality/device.py
# class VrDevice:
#     """Represents an OpenVR device."""
# 
#     def __init__(self, vr_system, index: int):
#         """Initializes a new VrDevice with the given device index."""
#         self._vr_system = vr_system
#         self._index = index
#         self._value_cache = {}
# 
#     @property
#     def index(self) -> int:
#         """Returns the device index."""
#         return self._index
# 
#     def is_connected(self) -> bool:
#         """Returns whether the device is connected."""
#         return self._vr_system.isTrackedDeviceConnected(self._index)
# 
#     def get_serial(self) -> str:
#         """Returns the serial number of the device."""
#         return self._get_string(openvr.Prop_SerialNumber_String)
# 
#     def get_model(self) -> str:
#         """Returns the model number of the device."""
#         return self._get_string(openvr.Prop_ModelNumber_String)
# 
#     def get_model_name(self) -> str:
#         """Returns the model name of the device."""
#         return self._get_string(openvr.Prop_RenderModelName_String)
# 
#     def get_summary(self) -> str:
#         """Returns a summary of information about the device."""
#         connected = self.is_connected()
#         info = '[{} - {}]'.format(self._index,
#                                   'Connected' if connected else 'Disconnected')
#         if connected:
#             info += ' {} ({})'.format(self.get_model_name(), self.get_serial())
#         return info
# 
#     def _get_string(self, prop_type) -> str:
#         """Returns a string property of the device."""
#         if prop_type in self._value_cache:
#             return self._value_cache[prop_type]
#         value = self._vr_system.getStringTrackedDeviceProperty(
#             self._index, prop_type).decode('utf-8')
#         self._value_cache[prop_type] = value
#         return value
# 
#     def _get_bool(self, prop_type) -> bool:
#         """Returns a boolean property of the device."""
#         if prop_type in self._value_cache:
#             return self._value_cache[prop_type]
#         value = self._vr_system.getBoolTrackedDeviceProperty(
#             self._index, prop_type)[0]
#         self._value_cache[prop_type] = value
#         return value
# 
#     def _get_float(self, prop_type) -> float:
#         """Returns a float property of the device."""
#         if prop_type in self._value_cache:
#             return self._value_cache[prop_type]
#         value = self._vr_system.getFloatTrackedDeviceProperty(
#             self._index, prop_type)[0]
#         self._value_cache[prop_type] = value
#         return value
# 
# Path: robel/components/tracking/virtual_reality/poses.py
# class VrPoseBatch:
#     """Represents a batch of poses calculated by the OpenVR system."""
# 
#     def __init__(self, vr_system, time_from_now: float = 0.0):
#         """Initializes a new pose batch."""
#         self._vr_system = vr_system
#         # Query poses for all devices.
#         self.poses = self._vr_system.getDeviceToAbsoluteTrackingPose(
#             openvr.TrackingUniverseStanding, time_from_now,
#             openvr.k_unMaxTrackedDeviceCount)
# 
#     def get_state(self, device: VrDevice) -> TrackerState:
#         """Returns the tracking state for the given device."""
#         if not self.poses[device.index].bPoseIsValid:
#             state = TrackerState()
#         else:
#             vr_pose = np.ctypeslib.as_array(
#                 self.poses[device.index].mDeviceToAbsoluteTracking[:],
#                 shape=(3, 4))
#             # Check that the pose is valid.
#             # If all of the translations are 0, get from the cache.
#             assert vr_pose.shape == (3, 4)
#             state = TrackerState(pos=vr_pose[:, 3], rot=vr_pose[:, :3])
#         return state


# Path: robel/components/tracking/virtual_reality/client.py
from typing import List, Union
from robel.components.tracking.virtual_reality.device import VrDevice
from robel.components.tracking.virtual_reality.poses import VrPoseBatch
import openvr

                'Could not find device with name or index: {} (Available: {})'
                .format(identifier, sorted(self._device_serial_lookup.keys())))

        if identifier in self._device_index_lookup:
            return self._device_index_lookup[identifier]
        return self._device_serial_lookup[identifier]

    def discover_devices(self) -> List[VrDevice]:
        """Returns and caches all connected devices."""
        self._device_index_lookup.clear()
        self._device_serial_lookup.clear()
        devices = []
        for device_index in range(openvr.k_unMaxTrackedDeviceCount):
            device = VrDevice(self._vr_system, device_index)
            if not device.is_connected():
                continue
            devices.append(device)
            self._device_index_lookup[str(device.index)] = device
            self._device_serial_lookup[device.get_serial()] = device
        self._devices = devices
        return devices

    def get_poses(self, time_from_now: float = 0.0,
                  update_plot: bool = True) -> VrPoseBatch:
        """Returns a batch of poses that can be queried per device.

        Args:
            time_from_now: The seconds into the future to read poses.
            update_plot: If True, updates an existing plot.
        """

        pose_batch = VrPoseBatch(self._vr_system, time_from_now)