viam-sdk 0.25.2__py3-none-linux_armv7l.whl → 0.62.0__py3-none-linux_armv7l.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- viam/app/_logs.py +3 -6
- viam/app/app_client.py +606 -262
- viam/app/billing_client.py +60 -18
- viam/app/data_client.py +1086 -315
- viam/app/ml_training_client.py +51 -48
- viam/app/provisioning_client.py +3 -5
- viam/app/viam_client.py +105 -11
- viam/components/arm/__init__.py +1 -25
- viam/components/arm/arm.py +21 -22
- viam/components/arm/client.py +27 -30
- viam/components/arm/service.py +3 -3
- viam/components/audio_in/__init__.py +24 -0
- viam/components/audio_in/audio_in.py +74 -0
- viam/components/audio_in/client.py +76 -0
- viam/components/audio_in/service.py +83 -0
- viam/components/audio_input/__init__.py +1 -1
- viam/components/audio_input/audio_input.py +4 -3
- viam/components/audio_input/client.py +19 -8
- viam/components/audio_input/service.py +10 -0
- viam/components/audio_out/__init__.py +21 -0
- viam/components/audio_out/audio_out.py +72 -0
- viam/components/audio_out/client.py +67 -0
- viam/components/audio_out/service.py +63 -0
- viam/components/base/__init__.py +2 -10
- viam/components/base/base.py +20 -20
- viam/components/base/client.py +27 -30
- viam/components/board/__init__.py +2 -25
- viam/components/board/board.py +39 -77
- viam/components/board/client.py +39 -73
- viam/components/button/__init__.py +10 -0
- viam/components/button/button.py +41 -0
- viam/components/button/client.py +52 -0
- viam/components/button/service.py +46 -0
- viam/components/camera/__init__.py +1 -1
- viam/components/camera/camera.py +31 -22
- viam/components/camera/client.py +30 -20
- viam/components/camera/service.py +14 -12
- viam/components/component_base.py +10 -7
- viam/components/encoder/__init__.py +1 -1
- viam/components/encoder/client.py +15 -16
- viam/components/encoder/encoder.py +9 -9
- viam/components/gantry/__init__.py +1 -13
- viam/components/gantry/client.py +41 -28
- viam/components/gantry/gantry.py +48 -17
- viam/components/gantry/service.py +21 -5
- viam/components/generic/__init__.py +1 -1
- viam/components/generic/client.py +11 -7
- viam/components/generic/generic.py +3 -3
- viam/components/gripper/__init__.py +3 -12
- viam/components/gripper/client.py +43 -20
- viam/components/gripper/gripper.py +87 -12
- viam/components/gripper/service.py +32 -3
- viam/components/input/__init__.py +1 -14
- viam/components/input/client.py +22 -23
- viam/components/input/input.py +18 -12
- viam/components/motor/__init__.py +1 -21
- viam/components/motor/client.py +36 -42
- viam/components/motor/motor.py +24 -24
- viam/components/movement_sensor/__init__.py +1 -1
- viam/components/movement_sensor/client.py +33 -40
- viam/components/movement_sensor/movement_sensor.py +12 -12
- viam/components/pose_tracker/__init__.py +1 -1
- viam/components/pose_tracker/client.py +9 -8
- viam/components/pose_tracker/pose_tracker.py +2 -2
- viam/components/power_sensor/__init__.py +1 -1
- viam/components/power_sensor/client.py +15 -18
- viam/components/power_sensor/power_sensor.py +12 -12
- viam/components/sensor/__init__.py +1 -1
- viam/components/sensor/client.py +9 -8
- viam/components/sensor/sensor.py +5 -5
- viam/components/servo/__init__.py +1 -13
- viam/components/servo/client.py +18 -18
- viam/components/servo/servo.py +12 -12
- viam/components/switch/__init__.py +10 -0
- viam/components/switch/client.py +83 -0
- viam/components/switch/service.py +72 -0
- viam/components/switch/switch.py +95 -0
- viam/gen/app/agent/v1/agent_pb2.py +40 -29
- viam/gen/app/agent/v1/agent_pb2.pyi +73 -11
- viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +45 -42
- viam/gen/app/data/v1/data_grpc.py +98 -2
- viam/gen/app/data/v1/data_pb2.py +238 -119
- viam/gen/app/data/v1/data_pb2.pyi +804 -34
- viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
- viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +57 -0
- viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +387 -0
- viam/gen/app/dataset/v1/dataset_grpc.py +10 -2
- viam/gen/app/dataset/v1/dataset_pb2.py +38 -31
- viam/gen/app/dataset/v1/dataset_pb2.pyi +36 -1
- viam/gen/app/datasync/v1/data_sync_grpc.py +1 -1
- viam/gen/app/datasync/v1/data_sync_pb2.py +61 -51
- viam/gen/app/datasync/v1/data_sync_pb2.pyi +52 -12
- viam/gen/app/mlinference/__init__.py +0 -0
- viam/gen/app/mlinference/v1/__init__.py +0 -0
- viam/gen/app/mlinference/v1/ml_inference_grpc.py +28 -0
- viam/gen/app/mlinference/v1/ml_inference_pb2.py +23 -0
- viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +63 -0
- viam/gen/app/mltraining/v1/ml_training_grpc.py +18 -2
- viam/gen/app/mltraining/v1/ml_training_pb2.py +134 -101
- viam/gen/app/mltraining/v1/ml_training_pb2.pyi +193 -7
- viam/gen/app/packages/v1/packages_pb2.py +43 -40
- viam/gen/app/v1/app_grpc.py +290 -2
- viam/gen/app/v1/app_pb2.py +670 -453
- viam/gen/app/v1/app_pb2.pyi +3133 -947
- viam/gen/app/v1/billing_grpc.py +34 -2
- viam/gen/app/v1/billing_pb2.py +94 -35
- viam/gen/app/v1/billing_pb2.pyi +314 -61
- viam/gen/app/v1/end_user_pb2.py +50 -29
- viam/gen/app/v1/robot_pb2.py +120 -111
- viam/gen/app/v1/robot_pb2.pyi +137 -15
- viam/gen/common/v1/common_pb2.py +86 -66
- viam/gen/common/v1/common_pb2.pyi +184 -8
- viam/gen/component/arm/v1/arm_grpc.py +18 -2
- viam/gen/component/arm/v1/arm_pb2.py +68 -55
- viam/gen/component/arm/v1/arm_pb2.pyi +73 -3
- viam/gen/component/audioin/__init__.py +0 -0
- viam/gen/component/audioin/v1/__init__.py +0 -0
- viam/gen/component/audioin/v1/audioin_grpc.py +54 -0
- viam/gen/component/audioin/v1/audioin_pb2.py +34 -0
- viam/gen/component/audioin/v1/audioin_pb2.pyi +94 -0
- viam/gen/component/audioinput/v1/audioinput_pb2.py +35 -32
- viam/gen/component/audioout/__init__.py +0 -0
- viam/gen/component/audioout/v1/__init__.py +0 -0
- viam/gen/component/audioout/v1/audioout_grpc.py +54 -0
- viam/gen/component/audioout/v1/audioout_pb2.py +32 -0
- viam/gen/component/audioout/v1/audioout_pb2.pyi +47 -0
- viam/gen/component/base/v1/base_pb2.py +57 -54
- viam/gen/component/board/v1/board_pb2.py +93 -90
- viam/gen/component/button/__init__.py +0 -0
- viam/gen/component/button/v1/__init__.py +0 -0
- viam/gen/component/button/v1/button_grpc.py +38 -0
- viam/gen/component/button/v1/button_pb2.py +28 -0
- viam/gen/component/button/v1/button_pb2.pyi +39 -0
- viam/gen/component/camera/v1/camera_pb2.py +58 -55
- viam/gen/component/camera/v1/camera_pb2.pyi +31 -7
- viam/gen/component/encoder/v1/encoder_pb2.py +35 -32
- viam/gen/component/gantry/v1/gantry_grpc.py +9 -1
- viam/gen/component/gantry/v1/gantry_pb2.py +56 -51
- viam/gen/component/generic/v1/generic_pb2.py +15 -12
- viam/gen/component/gripper/v1/gripper_grpc.py +18 -2
- viam/gen/component/gripper/v1/gripper_pb2.py +48 -37
- viam/gen/component/gripper/v1/gripper_pb2.pyi +43 -1
- viam/gen/component/inputcontroller/v1/input_controller_pb2.py +45 -42
- viam/gen/component/motor/v1/motor_pb2.py +77 -74
- viam/gen/component/movementsensor/v1/movementsensor_pb2.py +69 -66
- viam/gen/component/posetracker/v1/pose_tracker_pb2.py +25 -22
- viam/gen/component/powersensor/v1/powersensor_pb2.py +33 -30
- viam/gen/component/sensor/v1/sensor_pb2.py +17 -14
- viam/gen/component/servo/v1/servo_pb2.py +41 -38
- viam/gen/component/switch/__init__.py +0 -0
- viam/gen/component/switch/v1/__init__.py +0 -0
- viam/gen/component/switch/v1/switch_grpc.py +54 -0
- viam/gen/component/switch/v1/switch_pb2.py +40 -0
- viam/gen/component/switch/v1/switch_pb2.pyi +116 -0
- viam/gen/component/testecho/v1/testecho_pb2.py +29 -26
- viam/gen/module/v1/module_pb2.py +36 -33
- viam/gen/module/v1/module_pb2.pyi +7 -2
- viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +26 -23
- viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +23 -20
- viam/gen/proto/rpc/v1/auth_pb2.py +27 -24
- viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +35 -32
- viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +62 -57
- viam/gen/proto/rpc/webrtc/v1/signaling_pb2.pyi +18 -4
- viam/gen/provisioning/v1/provisioning_grpc.py +10 -2
- viam/gen/provisioning/v1/provisioning_pb2.py +38 -31
- viam/gen/provisioning/v1/provisioning_pb2.pyi +20 -2
- viam/gen/robot/v1/robot_grpc.py +61 -29
- viam/gen/robot/v1/robot_pb2.py +186 -155
- viam/gen/robot/v1/robot_pb2.pyi +278 -59
- viam/gen/service/datamanager/v1/data_manager_grpc.py +11 -2
- viam/gen/service/datamanager/v1/data_manager_pb2.py +27 -17
- viam/gen/service/datamanager/v1/data_manager_pb2.pyi +47 -1
- viam/gen/service/discovery/__init__.py +0 -0
- viam/gen/service/discovery/v1/__init__.py +0 -0
- viam/gen/service/discovery/v1/discovery_grpc.py +39 -0
- viam/gen/service/discovery/v1/discovery_pb2.py +29 -0
- viam/gen/service/discovery/v1/discovery_pb2.pyi +51 -0
- viam/gen/service/generic/v1/generic_pb2.py +13 -10
- viam/gen/service/mlmodel/v1/mlmodel_pb2.py +75 -72
- viam/gen/service/motion/v1/motion_pb2.py +118 -85
- viam/gen/service/motion/v1/motion_pb2.pyi +130 -68
- viam/gen/service/navigation/v1/navigation_pb2.py +75 -72
- viam/gen/service/sensors/v1/sensors_pb2.py +59 -56
- viam/gen/service/shell/v1/shell_pb2.py +35 -32
- viam/gen/service/slam/v1/slam_pb2.py +43 -40
- viam/gen/service/slam/v1/slam_pb2.pyi +1 -1
- viam/gen/service/video/__init__.py +0 -0
- viam/gen/service/video/v1/__init__.py +0 -0
- viam/gen/service/video/v1/video_grpc.py +39 -0
- viam/gen/service/video/v1/video_pb2.py +29 -0
- viam/gen/service/video/v1/video_pb2.pyi +72 -0
- viam/gen/service/vision/v1/vision_pb2.py +60 -57
- viam/gen/service/vision/v1/vision_pb2.pyi +28 -3
- viam/gen/service/worldstatestore/__init__.py +0 -0
- viam/gen/service/worldstatestore/v1/__init__.py +0 -0
- viam/gen/service/worldstatestore/v1/world_state_store_grpc.py +55 -0
- viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +39 -0
- viam/gen/service/worldstatestore/v1/world_state_store_pb2.pyi +171 -0
- viam/gen/stream/v1/stream_grpc.py +17 -1
- viam/gen/stream/v1/stream_pb2.py +34 -21
- viam/gen/stream/v1/stream_pb2.pyi +79 -1
- viam/gen/tagger/v1/tagger_pb2.py +9 -8
- viam/logging.py +77 -18
- viam/media/audio.py +28 -0
- viam/media/utils/pil/__init__.py +7 -3
- viam/media/video.py +80 -17
- viam/module/module.py +111 -38
- viam/module/resource_data_consumer.py +41 -0
- viam/module/service.py +9 -1
- viam/module/types.py +2 -4
- viam/proto/app/__init__.py +199 -0
- viam/proto/app/agent/__init__.py +5 -2
- viam/proto/app/billing.py +31 -4
- viam/proto/app/cloudslam/__init__.py +1 -0
- viam/proto/app/data/__init__.py +63 -0
- viam/proto/app/datapipelines/__init__.py +56 -0
- viam/proto/app/dataset/__init__.py +5 -0
- viam/proto/app/datasync/__init__.py +3 -0
- viam/proto/app/end_user.py +1 -0
- viam/proto/app/mlinference/__init__.py +15 -0
- viam/proto/app/mltraining/__init__.py +13 -0
- viam/proto/app/packages/__init__.py +1 -0
- viam/proto/app/robot.py +7 -0
- viam/proto/common/__init__.py +15 -0
- viam/proto/component/arm/__init__.py +7 -0
- viam/proto/component/audioin/__init__.py +16 -0
- viam/proto/component/audioinput/__init__.py +1 -0
- viam/proto/component/audioout/__init__.py +15 -0
- viam/proto/component/base/__init__.py +1 -0
- viam/proto/component/board/__init__.py +1 -0
- viam/proto/component/button/__init__.py +15 -0
- viam/proto/component/camera/__init__.py +1 -0
- viam/proto/component/encoder/__init__.py +1 -0
- viam/proto/component/gantry/__init__.py +1 -0
- viam/proto/component/generic/__init__.py +1 -0
- viam/proto/component/gripper/__init__.py +5 -0
- viam/proto/component/inputcontroller/__init__.py +1 -0
- viam/proto/component/motor/__init__.py +1 -0
- viam/proto/component/movementsensor/__init__.py +1 -0
- viam/proto/component/posetracker/__init__.py +1 -0
- viam/proto/component/powersensor/__init__.py +1 -0
- viam/proto/component/sensor/__init__.py +1 -0
- viam/proto/component/servo/__init__.py +1 -0
- viam/proto/component/switch/__init__.py +26 -0
- viam/proto/component/testecho/__init__.py +1 -0
- viam/proto/module/__init__.py +1 -0
- viam/proto/provisioning/__init__.py +5 -0
- viam/proto/robot/__init__.py +29 -8
- viam/proto/rpc/auth.py +1 -0
- viam/proto/rpc/examples/echo/__init__.py +1 -0
- viam/proto/rpc/examples/echoresource/__init__.py +1 -0
- viam/proto/rpc/webrtc/grpc.py +1 -0
- viam/proto/rpc/webrtc/signaling.py +3 -0
- viam/proto/service/datamanager/__init__.py +9 -1
- viam/proto/service/discovery/__init__.py +15 -0
- viam/proto/service/generic/__init__.py +1 -0
- viam/proto/service/mlmodel/__init__.py +1 -0
- viam/proto/service/motion/__init__.py +3 -0
- viam/proto/service/navigation/__init__.py +1 -0
- viam/proto/service/sensors/__init__.py +1 -0
- viam/proto/service/shell/__init__.py +1 -0
- viam/proto/service/slam/__init__.py +1 -0
- viam/proto/service/video/__init__.py +15 -0
- viam/proto/service/vision/__init__.py +1 -0
- viam/proto/service/worldstatestore/__init__.py +32 -0
- viam/proto/stream/__init__.py +11 -0
- viam/py.typed +0 -0
- viam/resource/base.py +12 -8
- viam/resource/easy_resource.py +24 -13
- viam/resource/manager.py +6 -5
- viam/resource/registry.py +39 -51
- viam/resource/rpc_client_base.py +33 -1
- viam/resource/types.py +13 -14
- viam/robot/client.py +190 -122
- viam/robot/service.py +2 -50
- viam/rpc/dial.py +54 -4
- viam/rpc/libviam_rust_utils.so +0 -0
- viam/rpc/server.py +25 -11
- viam/rpc/types.py +2 -4
- viam/services/discovery/__init__.py +12 -0
- viam/services/discovery/client.py +55 -0
- viam/services/discovery/discovery.py +52 -0
- viam/services/discovery/service.py +43 -0
- viam/services/generic/__init__.py +1 -1
- viam/services/generic/client.py +8 -5
- viam/services/generic/generic.py +2 -2
- viam/services/mlmodel/__init__.py +1 -1
- viam/services/mlmodel/client.py +17 -7
- viam/services/mlmodel/mlmodel.py +23 -12
- viam/services/mlmodel/service.py +5 -2
- viam/services/mlmodel/utils.py +11 -1
- viam/services/motion/__init__.py +2 -2
- viam/services/motion/client.py +32 -32
- viam/services/motion/motion.py +66 -62
- viam/services/navigation/__init__.py +1 -1
- viam/services/navigation/client.py +30 -20
- viam/services/navigation/navigation.py +23 -23
- viam/services/service_base.py +13 -9
- viam/services/service_client_base.py +3 -3
- viam/services/slam/__init__.py +1 -1
- viam/services/slam/client.py +15 -10
- viam/services/slam/slam.py +11 -11
- viam/services/vision/__init__.py +1 -1
- viam/services/vision/client.py +31 -24
- viam/services/vision/service.py +8 -8
- viam/services/vision/vision.py +36 -53
- viam/services/worldstatestore/__init__.py +18 -0
- viam/services/worldstatestore/client.py +94 -0
- viam/services/worldstatestore/service.py +55 -0
- viam/services/worldstatestore/worldstatestore.py +90 -0
- viam/sessions_client.py +115 -46
- viam/streams.py +3 -6
- viam/utils.py +44 -14
- viam/version_metadata.py +4 -0
- {viam_sdk-0.25.2.dist-info → viam_sdk-0.62.0.dist-info}/METADATA +27 -28
- viam_sdk-0.62.0.dist-info/RECORD +514 -0
- {viam_sdk-0.25.2.dist-info → viam_sdk-0.62.0.dist-info}/WHEEL +1 -1
- viam/gen/proto/rpc/examples/fileupload/v1/fileupload_grpc.py +0 -27
- viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.py +0 -18
- viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.pyi +0 -45
- viam/proto/rpc/examples/fileupload/__init__.py +0 -18
- viam/services/sensors/__init__.py +0 -5
- viam/services/sensors/client.py +0 -65
- viam_sdk-0.25.2.dist-info/LICENSE +0 -202
- viam_sdk-0.25.2.dist-info/RECORD +0 -442
- /viam/gen/{proto/rpc/examples/fileupload → app/datapipelines}/__init__.py +0 -0
- /viam/gen/{proto/rpc/examples/fileupload → app/datapipelines}/v1/__init__.py +0 -0
- /LICENSE → /viam_sdk-0.62.0.dist-info/licenses/LICENSE +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import Any, AsyncGenerator, Final, List, Mapping, Optional
|
|
3
|
+
|
|
4
|
+
from viam.proto.common import Transform
|
|
5
|
+
from viam.proto.service.worldstatestore import (
|
|
6
|
+
StreamTransformChangesResponse,
|
|
7
|
+
)
|
|
8
|
+
from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_SERVICE
|
|
9
|
+
|
|
10
|
+
from ..service_base import ServiceBase
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class WorldStateStore(ServiceBase):
|
|
14
|
+
"""WorldStateStore is a Viam service that manages world state transforms.
|
|
15
|
+
|
|
16
|
+
The WorldStateStore service provides functionality to store, retrieve, and stream
|
|
17
|
+
changes to world state transforms, which represent the pose of objects in different
|
|
18
|
+
reference frames. This functionality can be used to create custom visualizations of the world state.
|
|
19
|
+
|
|
20
|
+
For more information, see `WorldStateStore service <https://docs.viam.com/dev/reference/apis/services/world-state-store/>`_.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
API: Final = API( # pyright: ignore [reportIncompatibleVariableOverride]
|
|
24
|
+
RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_SERVICE, "world_state_store"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@abc.abstractmethod
|
|
28
|
+
async def list_uuids(
|
|
29
|
+
self,
|
|
30
|
+
*,
|
|
31
|
+
extra: Optional[Mapping[str, Any]] = None,
|
|
32
|
+
timeout: Optional[float] = None,
|
|
33
|
+
) -> List[bytes]:
|
|
34
|
+
"""List all world state transform UUIDs.
|
|
35
|
+
|
|
36
|
+
::
|
|
37
|
+
|
|
38
|
+
worldstatestore = WorldStateStoreClient.from_robot(robot=machine, name="builtin")
|
|
39
|
+
|
|
40
|
+
uuids = await worldstatestore.list_uuids()
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List[bytes]: A list of transform UUIDs
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
@abc.abstractmethod
|
|
48
|
+
async def get_transform(
|
|
49
|
+
self,
|
|
50
|
+
uuid: bytes,
|
|
51
|
+
*,
|
|
52
|
+
extra: Optional[Mapping[str, Any]] = None,
|
|
53
|
+
timeout: Optional[float] = None,
|
|
54
|
+
) -> Transform:
|
|
55
|
+
"""Get a world state transform by UUID.
|
|
56
|
+
|
|
57
|
+
::
|
|
58
|
+
|
|
59
|
+
worldstatestore = WorldStateStoreClient.from_robot(robot=machine, name="builtin")
|
|
60
|
+
|
|
61
|
+
transform = await worldstatestore.get_transform(uuid=b"some-uuid")
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
uuid (bytes): The UUID of the transform to retrieve
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Transform: The requested transform
|
|
68
|
+
"""
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
@abc.abstractmethod
|
|
72
|
+
async def stream_transform_changes(
|
|
73
|
+
self,
|
|
74
|
+
*,
|
|
75
|
+
extra: Optional[Mapping[str, Any]] = None,
|
|
76
|
+
timeout: Optional[float] = None,
|
|
77
|
+
) -> AsyncGenerator[StreamTransformChangesResponse, None]:
|
|
78
|
+
"""Stream changes to world state transforms.
|
|
79
|
+
|
|
80
|
+
::
|
|
81
|
+
|
|
82
|
+
worldstatestore = WorldStateStoreClient.from_robot(robot=machine, name="builtin")
|
|
83
|
+
|
|
84
|
+
async for change in worldstatestore.stream_transform_changes():
|
|
85
|
+
print(f"Transform {change.transform.uuid} {change.change_type}")
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
AsyncGenerator[StreamTransformChangesResponse, None]: A stream of transform changes
|
|
89
|
+
"""
|
|
90
|
+
...
|
viam/sessions_client.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import importlib
|
|
3
|
+
import pkgutil
|
|
4
|
+
import sys
|
|
5
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
2
7
|
from copy import deepcopy
|
|
3
8
|
from datetime import timedelta
|
|
4
9
|
from enum import IntEnum
|
|
5
10
|
from threading import Lock, Thread
|
|
6
|
-
from typing import Optional
|
|
11
|
+
from typing import MutableMapping, Optional
|
|
7
12
|
|
|
8
13
|
from grpclib import Status
|
|
9
14
|
from grpclib.client import Channel
|
|
@@ -12,26 +17,13 @@ from grpclib.exceptions import GRPCError, StreamTerminatedError
|
|
|
12
17
|
from grpclib.metadata import _MetadataLike
|
|
13
18
|
|
|
14
19
|
from viam import logging
|
|
20
|
+
from viam.gen.common.v1.common_pb2 import safety_heartbeat_monitored
|
|
15
21
|
from viam.proto.robot import RobotServiceStub, SendSessionHeartbeatRequest, StartSessionRequest, StartSessionResponse
|
|
16
22
|
from viam.rpc.dial import DialOptions, dial
|
|
17
23
|
|
|
18
24
|
LOGGER = logging.getLogger(__name__)
|
|
19
25
|
SESSION_METADATA_KEY = "viam-sid"
|
|
20
26
|
|
|
21
|
-
EXEMPT_METADATA_METHODS = frozenset(
|
|
22
|
-
[
|
|
23
|
-
"/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo",
|
|
24
|
-
"/proto.rpc.webrtc.v1.SignalingService/Call",
|
|
25
|
-
"/proto.rpc.webrtc.v1.SignalingService/CallUpdate",
|
|
26
|
-
"/proto.rpc.webrtc.v1.SignalingService/OptionalWebRTCConfig",
|
|
27
|
-
"/proto.rpc.v1.AuthService/Authenticate",
|
|
28
|
-
"/viam.robot.v1.RobotService/ResourceNames",
|
|
29
|
-
"/viam.robot.v1.RobotService/ResourceRPCSubtypes",
|
|
30
|
-
"/viam.robot.v1.RobotService/StartSession",
|
|
31
|
-
"/viam.robot.v1.RobotService/SendSessionHeartbeat",
|
|
32
|
-
]
|
|
33
|
-
)
|
|
34
|
-
|
|
35
27
|
|
|
36
28
|
class _SupportedState(IntEnum):
|
|
37
29
|
UNKNOWN = 0
|
|
@@ -47,7 +39,8 @@ class SessionsClient:
|
|
|
47
39
|
|
|
48
40
|
channel: Channel
|
|
49
41
|
client: RobotServiceStub
|
|
50
|
-
_address: str
|
|
42
|
+
_address: str # direct dial address, when using webRTC this is the local socket rather than a robot address
|
|
43
|
+
_robot_address: Optional[str] # the actual machine address on app.viam.com. important for creating a sessions client on Windows
|
|
51
44
|
_dial_options: DialOptions
|
|
52
45
|
_disabled: bool
|
|
53
46
|
_lock: Lock
|
|
@@ -55,19 +48,33 @@ class SessionsClient:
|
|
|
55
48
|
_heartbeat_interval: Optional[timedelta]
|
|
56
49
|
_supported: _SupportedState
|
|
57
50
|
_thread: Optional[Thread]
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
_pool: ThreadPoolExecutor
|
|
52
|
+
|
|
53
|
+
_HEARTBEAT_MONITORED_METHODS: MutableMapping[str, bool] = {}
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
channel: Channel,
|
|
58
|
+
direct_dial_address: str,
|
|
59
|
+
dial_options: Optional[DialOptions],
|
|
60
|
+
*,
|
|
61
|
+
disabled: bool = False,
|
|
62
|
+
robot_addr: Optional[str] = None,
|
|
63
|
+
):
|
|
60
64
|
self.channel = channel
|
|
61
65
|
self.client = RobotServiceStub(channel)
|
|
62
66
|
self._address = direct_dial_address
|
|
67
|
+
self._robot_address = robot_addr
|
|
63
68
|
self._disabled = disabled
|
|
64
69
|
self._dial_options = deepcopy(dial_options) if dial_options is not None else DialOptions()
|
|
65
|
-
|
|
70
|
+
if sys.platform != "win32" and sys.platform != "cygwin":
|
|
71
|
+
self._dial_options.disable_webrtc = True
|
|
66
72
|
self._lock = Lock()
|
|
67
73
|
self._current_id = ""
|
|
68
74
|
self._heartbeat_interval = None
|
|
69
75
|
self._supported = _SupportedState.UNKNOWN
|
|
70
76
|
self._thread = None
|
|
77
|
+
self._pool = ThreadPoolExecutor()
|
|
71
78
|
|
|
72
79
|
listen(self.channel, SendRequest, self._send_request)
|
|
73
80
|
listen(self.channel, RecvTrailingMetadata, self._recv_trailers)
|
|
@@ -92,7 +99,7 @@ class SessionsClient:
|
|
|
92
99
|
if self._disabled:
|
|
93
100
|
return
|
|
94
101
|
|
|
95
|
-
if event.method_name
|
|
102
|
+
if not self._is_safety_heartbeat_monitored(event.method_name):
|
|
96
103
|
return
|
|
97
104
|
|
|
98
105
|
event.metadata.update(await self.metadata)
|
|
@@ -102,39 +109,45 @@ class SessionsClient:
|
|
|
102
109
|
LOGGER.debug("Session expired")
|
|
103
110
|
self.reset()
|
|
104
111
|
|
|
112
|
+
@asynccontextmanager
|
|
113
|
+
async def _acquire_lock_async(self):
|
|
114
|
+
loop = asyncio.get_event_loop()
|
|
115
|
+
await loop.run_in_executor(self._pool, self._lock.acquire)
|
|
116
|
+
try:
|
|
117
|
+
yield
|
|
118
|
+
finally:
|
|
119
|
+
self._lock.release()
|
|
120
|
+
|
|
105
121
|
@property
|
|
106
122
|
async def metadata(self) -> _MetadataLike:
|
|
107
|
-
with self.
|
|
123
|
+
async with self._acquire_lock_async():
|
|
108
124
|
if self._disabled or self._supported != _SupportedState.UNKNOWN:
|
|
109
125
|
return self._metadata
|
|
110
126
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
with self._lock:
|
|
127
|
+
request = StartSessionRequest(resume=self._current_id)
|
|
128
|
+
try:
|
|
129
|
+
response: StartSessionResponse = await self.client.StartSession(request)
|
|
130
|
+
except GRPCError as error:
|
|
131
|
+
if error.status == Status.UNIMPLEMENTED:
|
|
117
132
|
self._reset()
|
|
118
133
|
self._supported = _SupportedState.FALSE
|
|
119
134
|
return self._metadata
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
else:
|
|
136
|
+
raise
|
|
122
137
|
|
|
123
|
-
|
|
124
|
-
|
|
138
|
+
if response is None:
|
|
139
|
+
raise GRPCError(status=Status.INTERNAL, message="Expected response to start session")
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
|
|
141
|
+
if response.heartbeat_window is None:
|
|
142
|
+
raise GRPCError(status=Status.INTERNAL, message="Expected heartbeat window in response to start session")
|
|
128
143
|
|
|
129
|
-
with self._lock:
|
|
130
144
|
self._supported = _SupportedState.TRUE
|
|
131
145
|
self._heartbeat_interval = response.heartbeat_window.ToTimedelta()
|
|
132
146
|
self._current_id = response.id
|
|
133
147
|
|
|
134
|
-
|
|
135
|
-
|
|
148
|
+
# tick once to ensure heartbeats are supported
|
|
149
|
+
await self._heartbeat_tick(self.client)
|
|
136
150
|
|
|
137
|
-
with self._lock:
|
|
138
151
|
if self._thread is not None:
|
|
139
152
|
self._reset()
|
|
140
153
|
if self._supported == _SupportedState.TRUE:
|
|
@@ -153,28 +166,38 @@ class SessionsClient:
|
|
|
153
166
|
return self._metadata
|
|
154
167
|
|
|
155
168
|
async def _heartbeat_tick(self, client: RobotServiceStub):
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
request = SendSessionHeartbeatRequest(id=self._current_id)
|
|
169
|
+
if not self._current_id:
|
|
170
|
+
LOGGER.debug("Failed to send heartbeat, session client reset")
|
|
171
|
+
return
|
|
172
|
+
request = SendSessionHeartbeatRequest(id=self._current_id)
|
|
161
173
|
|
|
162
174
|
try:
|
|
163
175
|
await client.SendSessionHeartbeat(request)
|
|
164
176
|
except (GRPCError, StreamTerminatedError):
|
|
165
177
|
LOGGER.debug("Heartbeat terminated", exc_info=True)
|
|
166
|
-
self.
|
|
178
|
+
self._reset()
|
|
167
179
|
else:
|
|
168
180
|
LOGGER.debug("Sent heartbeat successfully")
|
|
169
181
|
|
|
182
|
+
def _get_local_addr(self) -> str:
|
|
183
|
+
if sys.platform != "win32" and sys.platform != "cygwin":
|
|
184
|
+
# if we're not on windows, we want the direct dial address
|
|
185
|
+
return self._address
|
|
186
|
+
|
|
187
|
+
# return `robot_address` if it exists, otherwise fallback
|
|
188
|
+
# when using TCP (i.e., on Windows), we need to create a connection to the actual
|
|
189
|
+
# robot address for a sessions client to maintain connectivity successfully
|
|
190
|
+
return self._robot_address if self._robot_address is not None else self._address
|
|
191
|
+
|
|
170
192
|
async def _heartbeat_process(self, wait: float):
|
|
171
|
-
|
|
193
|
+
addr = self._get_local_addr()
|
|
194
|
+
channel = await dial(address=addr, options=self._dial_options)
|
|
172
195
|
client = RobotServiceStub(channel.channel)
|
|
173
196
|
while True:
|
|
174
|
-
with self.
|
|
197
|
+
async with self._acquire_lock_async():
|
|
175
198
|
if self._supported != _SupportedState.TRUE:
|
|
176
199
|
return
|
|
177
|
-
|
|
200
|
+
await self._heartbeat_tick(client)
|
|
178
201
|
await asyncio.sleep(wait)
|
|
179
202
|
|
|
180
203
|
@property
|
|
@@ -183,3 +206,49 @@ class SessionsClient:
|
|
|
183
206
|
return {SESSION_METADATA_KEY: self._current_id}
|
|
184
207
|
|
|
185
208
|
return {}
|
|
209
|
+
|
|
210
|
+
def _is_safety_heartbeat_monitored(self, method: str) -> bool:
|
|
211
|
+
if method in self._HEARTBEAT_MONITORED_METHODS:
|
|
212
|
+
return self._HEARTBEAT_MONITORED_METHODS[method]
|
|
213
|
+
|
|
214
|
+
parts = method.split("/")
|
|
215
|
+
if len(parts) != 3:
|
|
216
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = False
|
|
217
|
+
return False
|
|
218
|
+
service_path = parts[1]
|
|
219
|
+
method_name = parts[2]
|
|
220
|
+
|
|
221
|
+
parts = service_path.split(".")
|
|
222
|
+
if len(parts) < 5:
|
|
223
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = False
|
|
224
|
+
return False
|
|
225
|
+
if parts[0] != "viam":
|
|
226
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = False
|
|
227
|
+
return False
|
|
228
|
+
resource_type = parts[1]
|
|
229
|
+
resource_subtype = parts[2]
|
|
230
|
+
version = parts[3]
|
|
231
|
+
service_name = parts[4]
|
|
232
|
+
try:
|
|
233
|
+
module = importlib.import_module(f"viam.gen.{resource_type}.{resource_subtype}.{version}")
|
|
234
|
+
submods = pkgutil.iter_modules(module.__path__)
|
|
235
|
+
for mod in submods:
|
|
236
|
+
if "_pb2" in mod.name:
|
|
237
|
+
submod = getattr(module, mod.name)
|
|
238
|
+
DESCRIPTOR = getattr(submod, "DESCRIPTOR")
|
|
239
|
+
for service in DESCRIPTOR.services_by_name.values():
|
|
240
|
+
if service.name == service_name:
|
|
241
|
+
for method_actual in service.methods:
|
|
242
|
+
if method_actual.name == method_name:
|
|
243
|
+
options = method_actual.GetOptions()
|
|
244
|
+
if options.HasExtension(safety_heartbeat_monitored):
|
|
245
|
+
is_monitored = options.Extensions[safety_heartbeat_monitored]
|
|
246
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = is_monitored
|
|
247
|
+
return is_monitored
|
|
248
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = False
|
|
249
|
+
return False
|
|
250
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = False
|
|
251
|
+
return False
|
|
252
|
+
except Exception:
|
|
253
|
+
self._HEARTBEAT_MONITORED_METHODS[method] = False
|
|
254
|
+
return False
|
viam/streams.py
CHANGED
|
@@ -11,8 +11,7 @@ StreamType = TypeVar("StreamType", covariant=True)
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Stream(Protocol[StreamType]):
|
|
14
|
-
async def next(self) -> StreamType:
|
|
15
|
-
...
|
|
14
|
+
async def next(self) -> StreamType: ...
|
|
16
15
|
|
|
17
16
|
def __aiter__(self) -> AsyncIterator:
|
|
18
17
|
return self
|
|
@@ -22,13 +21,11 @@ class Stream(Protocol[StreamType]):
|
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
class StreamReader(Protocol[StreamType]):
|
|
25
|
-
async def read(self) -> StreamType:
|
|
26
|
-
...
|
|
24
|
+
async def read(self) -> StreamType: ...
|
|
27
25
|
|
|
28
26
|
|
|
29
27
|
class StreamSource(Protocol[StreamType]):
|
|
30
|
-
async def stream(self) -> Stream[StreamType]:
|
|
31
|
-
...
|
|
28
|
+
async def stream(self) -> Stream[StreamType]: ...
|
|
32
29
|
|
|
33
30
|
|
|
34
31
|
class StreamWithIterator(Stream[StreamType]):
|
viam/utils.py
CHANGED
|
@@ -4,7 +4,7 @@ import functools
|
|
|
4
4
|
import sys
|
|
5
5
|
import threading
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from typing import Any, Dict, List, Mapping, Optional, SupportsBytes, SupportsFloat, Type, TypeVar, Union
|
|
7
|
+
from typing import Any, Callable, Dict, List, Mapping, Optional, SupportsBytes, SupportsFloat, Type, TypeVar, Union
|
|
8
8
|
|
|
9
9
|
from google.protobuf.json_format import MessageToDict, ParseDict
|
|
10
10
|
from google.protobuf.message import Message
|
|
@@ -15,7 +15,8 @@ from viam.proto.app.data import CaptureInterval, Filter, TagsFilter
|
|
|
15
15
|
from viam.proto.common import Geometry, GeoPoint, GetGeometriesRequest, GetGeometriesResponse, Orientation, ResourceName, Vector3
|
|
16
16
|
from viam.resource.base import ResourceBase
|
|
17
17
|
from viam.resource.registry import Registry
|
|
18
|
-
from viam.resource.
|
|
18
|
+
from viam.resource.rpc_client_base import ResourceRPCClientBase
|
|
19
|
+
from viam.resource.types import API, SupportsGetGeometries
|
|
19
20
|
|
|
20
21
|
if sys.version_info >= (3, 9):
|
|
21
22
|
from collections.abc import Callable
|
|
@@ -103,14 +104,10 @@ def resource_names_for_resource(resource: ResourceBase) -> List[ResourceName]:
|
|
|
103
104
|
rns: List[ResourceName] = []
|
|
104
105
|
|
|
105
106
|
for klass in resource.__class__.mro():
|
|
106
|
-
for registration in Registry.
|
|
107
|
+
for registration in Registry.REGISTERED_APIS().values():
|
|
107
108
|
if klass is registration.resource_type:
|
|
108
|
-
|
|
109
|
-
rns.append(
|
|
110
|
-
ResourceName(
|
|
111
|
-
namespace=subtype.namespace, type=subtype.resource_type, subtype=subtype.resource_subtype, name=resource.name
|
|
112
|
-
)
|
|
113
|
-
)
|
|
109
|
+
api: API = registration.resource_type.API
|
|
110
|
+
rns.append(ResourceName(namespace=api.namespace, type=api.resource_type, subtype=api.resource_subtype, name=resource.name))
|
|
114
111
|
return rns
|
|
115
112
|
|
|
116
113
|
|
|
@@ -134,7 +131,7 @@ def struct_to_message(struct: Struct, message_type: Type[_T]) -> _T:
|
|
|
134
131
|
return ParseDict(dct, message_type())
|
|
135
132
|
|
|
136
133
|
|
|
137
|
-
def dict_to_struct(obj: Mapping[str, ValueTypes]) -> Struct:
|
|
134
|
+
def dict_to_struct(obj: Optional[Mapping[str, ValueTypes]]) -> Struct:
|
|
138
135
|
def _convert(v: ValueTypes) -> Any:
|
|
139
136
|
if isinstance(v, bool):
|
|
140
137
|
return v
|
|
@@ -148,6 +145,8 @@ def dict_to_struct(obj: Mapping[str, ValueTypes]) -> Struct:
|
|
|
148
145
|
return {k: _convert(vv) for (k, vv) in v.items()}
|
|
149
146
|
return v
|
|
150
147
|
|
|
148
|
+
if obj is None:
|
|
149
|
+
obj = {}
|
|
151
150
|
struct = Struct()
|
|
152
151
|
struct.update({k: _convert(v) for (k, v) in obj.items()})
|
|
153
152
|
return struct
|
|
@@ -166,12 +165,15 @@ def datetime_to_timestamp(dt: Optional[datetime]) -> Optional[Timestamp]:
|
|
|
166
165
|
|
|
167
166
|
|
|
168
167
|
async def get_geometries(
|
|
169
|
-
client: SupportsGetGeometries,
|
|
168
|
+
client: SupportsGetGeometries,
|
|
169
|
+
name: str,
|
|
170
|
+
extra: Optional[Dict[str, Any]] = None,
|
|
171
|
+
timeout: Optional[float] = None,
|
|
172
|
+
metadata: ResourceRPCClientBase.Metadata = ResourceRPCClientBase.Metadata(),
|
|
170
173
|
) -> List[Geometry]:
|
|
171
|
-
|
|
172
|
-
extra = {}
|
|
174
|
+
md = metadata.proto
|
|
173
175
|
request = GetGeometriesRequest(name=name, extra=dict_to_struct(extra))
|
|
174
|
-
response: GetGeometriesResponse = await client.GetGeometries(request, timeout=timeout)
|
|
176
|
+
response: GetGeometriesResponse = await client.GetGeometries(request, timeout=timeout, metadata=md)
|
|
175
177
|
return [geometry for geometry in response.geometries]
|
|
176
178
|
|
|
177
179
|
|
|
@@ -333,3 +335,31 @@ def create_filter(
|
|
|
333
335
|
bbox_labels=bbox_labels,
|
|
334
336
|
dataset_id=dataset_id if dataset_id else "",
|
|
335
337
|
)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _alias_param(param_name: str, param_alias: str) -> Callable:
|
|
341
|
+
"""
|
|
342
|
+
Decorator for aliasing a param in a function. Intended for providing backwards compatibility on params with name changes.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
param_name: name of param in function to alias
|
|
346
|
+
param_alias: alias that can be used for this param
|
|
347
|
+
Returns:
|
|
348
|
+
The input function, plus param alias.
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
def decorator(func: Callable):
|
|
352
|
+
@functools.wraps(func)
|
|
353
|
+
def wrapper(*args, **kwargs):
|
|
354
|
+
alias_param_value = kwargs.get(param_alias)
|
|
355
|
+
if alias_param_value:
|
|
356
|
+
# Only use alias value if param is not given.
|
|
357
|
+
if not kwargs.get(param_name):
|
|
358
|
+
kwargs[param_name] = alias_param_value
|
|
359
|
+
del kwargs[param_alias]
|
|
360
|
+
result = func(*args, **kwargs)
|
|
361
|
+
return result
|
|
362
|
+
|
|
363
|
+
return wrapper
|
|
364
|
+
|
|
365
|
+
return decorator
|
viam/version_metadata.py
ADDED
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: viam-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.62.0
|
|
4
4
|
Summary: Viam Robotics Python SDK
|
|
5
|
-
|
|
6
|
-
License: Apache-2.0
|
|
7
|
-
Author: Naveed
|
|
8
|
-
Author-email: naveed@viam.com
|
|
9
|
-
Requires-Python: >=3.8.1,<3.13
|
|
10
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
-
Provides-Extra: mlmodel
|
|
17
|
-
Requires-Dist: googleapis-common-protos (>=1.60.0,<2)
|
|
18
|
-
Requires-Dist: grpclib (>=0.4.7,<1)
|
|
19
|
-
Requires-Dist: numpy (>=1.21,<2) ; extra == "mlmodel"
|
|
20
|
-
Requires-Dist: protobuf (>=4.24.3)
|
|
21
|
-
Requires-Dist: typing-extensions (>=4.8.0,<5)
|
|
5
|
+
Project-URL: Homepage, https://www.viam.com
|
|
22
6
|
Project-URL: Documentation, https://python.viam.dev
|
|
23
7
|
Project-URL: Repository, https://github.com/viamrobotics/viam-python-sdk
|
|
8
|
+
Author-email: Naveed Jooma <naveed@viam.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.8.1
|
|
12
|
+
Requires-Dist: googleapis-common-protos>=1.65.0
|
|
13
|
+
Requires-Dist: grpclib>=0.4.7
|
|
14
|
+
Requires-Dist: protobuf==5.29.5
|
|
15
|
+
Requires-Dist: pymongo>=4.10.1
|
|
16
|
+
Requires-Dist: typing-extensions>=4.12.2
|
|
17
|
+
Provides-Extra: mlmodel
|
|
18
|
+
Requires-Dist: numpy; extra == 'mlmodel'
|
|
24
19
|
Description-Content-Type: text/markdown
|
|
25
20
|
|
|
26
21
|
# Viam Python SDK
|
|
@@ -43,14 +38,18 @@ Currently, we have pre-built binaries for macOS (both Intel `x86_64` and Apple S
|
|
|
43
38
|
|
|
44
39
|
`pip install viam-sdk`
|
|
45
40
|
|
|
41
|
+
If you want to install on Windows, you can install from github directly with `pip`:
|
|
42
|
+
|
|
43
|
+
`pip install git+https://github.com/viamrobotics/viam-python-sdk.git`
|
|
44
|
+
|
|
45
|
+
Note that only direct gRPC connections are supported on Windows; you will need to [disable webrtc](https://python.viam.dev/autoapi/viam/rpc/dial/index.html#viam.rpc.dial.DialOptions.disable_webrtc) or else connection will fail. Full support (including webRTC) _does_ exist on WSL.
|
|
46
|
+
|
|
46
47
|
If you intend to use the [`MLModel` service](https://python.viam.dev/autoapi/viam/services/mlmodel/mlmodel/index.html#viam.services.mlmodel.mlmodel.MLModel), use the following command instead, which installs additional required dependencies:
|
|
47
48
|
|
|
48
49
|
`pip install 'viam-sdk[mlmodel]'`
|
|
49
50
|
|
|
50
51
|
You can also run this command on an existing Python SDK install to add support for the ML model service.
|
|
51
|
-
See the [ML (machine learning) model service](https://docs.viam.com/
|
|
52
|
-
|
|
53
|
-
Windows is not supported. If you are using Windows, install `viam-sdk` in WSL. For other unsupported systems, read further on how to install from source.
|
|
52
|
+
See the [ML (machine learning) model service](https://docs.viam.com/data-ai/ai/deploy/) documentation for more information.
|
|
54
53
|
|
|
55
54
|
### Upgrading
|
|
56
55
|
|
|
@@ -70,7 +69,7 @@ The Viam Python SDK uses native libraries to support communication over WebRTC,
|
|
|
70
69
|
- If you provided the `--release` flag, the enclosing directory will be `release`: `rust-utils/target/release/libviam_rust_utils.*`
|
|
71
70
|
- The extension of the executable will depend on your operating system. For example, on macOS it will be `libviam_rust_utils.dylib`, whereas on Linux it will be `libviam_rust_utils.so`
|
|
72
71
|
1. Copy the compiled library to the directory `viam-python-sdk/src/viam/rpc/`
|
|
73
|
-
1. From the `viam-python-sdk` directory, run `
|
|
72
|
+
1. From the `viam-python-sdk` directory, run `uv build --wheel` to create an installable package
|
|
74
73
|
1. Find the newly created installable package located in `viam-python-sdk/dist/` and pip install it directly, for example: `pip install viam-python-sdk/dist/viam_sdk-0.1.0-py3-none-any.whl`
|
|
75
74
|
|
|
76
75
|
If you have a macOS or Linux based operating system and do not want to build rust-utils manually, you can also look for the executable in the [releases](https://github.com/viamrobotics/rust-utils/releases/latest) page of the rust-utils library.
|
|
@@ -78,7 +77,7 @@ If you have a macOS or Linux based operating system and do not want to build rus
|
|
|
78
77
|
If you do **NOT** need communication over WebRTC (and thus, do not need the native library), the steps are:
|
|
79
78
|
|
|
80
79
|
1. Download/clone this repository
|
|
81
|
-
1. Run `
|
|
80
|
+
1. Run `uv build --wheel` from the `viam-python-sdk` directory
|
|
82
81
|
1. Find the newly created installable package located in `viam-python-sdk/dist/` and pip install it directly, for example: `pip install viam-python-sdk/dist/viam_sdk-0.1.0-py3-none-any.whl`
|
|
83
82
|
1. Ensure that every connection has the option `disable_webrtc` set to `True`: `viam.rpc.dial.DialOptions(disable_webrtc=True)`
|
|
84
83
|
- For more information about connecting to a robot, see the [documentation](https://python.viam.dev) and [example usage](https://python.viam.dev/examples/example.html)
|
|
@@ -92,7 +91,8 @@ To create a client application, to navigate to [app.viam.com](https://app.viam.c
|
|
|
92
91
|
1. Create a location (for example `home`)
|
|
93
92
|
2. Create a robot (for example `arduino`)
|
|
94
93
|
3. Follow the steps on the setup tab:
|
|
95
|
-
|
|
94
|
+
|
|
95
|
+
1. Setup machine cloud credentials on Single Board Computer (SBC)
|
|
96
96
|
2. Download and Install Viam Server
|
|
97
97
|
3. Wait until the robot shows as connected. If this doesn't happen try restarting the viam-server:
|
|
98
98
|
|
|
@@ -146,13 +146,12 @@ The SDK provides a number of abstract base components and services (collectively
|
|
|
146
146
|
1. Define all requirements of the resource in `{RESOURCE_NAME}.py`
|
|
147
147
|
1. Implement the gRPC service for the new resource in `service.py`
|
|
148
148
|
1. Create a gRPC client for the new resource in `client.py`
|
|
149
|
-
1. Register the
|
|
149
|
+
1. Register the API and define package exports in `__init__.py`
|
|
150
150
|
1. Write tests for the new resource and add the resource to `tests.mocks.{components|services}`
|
|
151
151
|
1. If the resource is a component, add the component to `examples.server.v1.components` and its corresponding concrete type in `examples.server.v1.server`
|
|
152
152
|
|
|
153
153
|
## License
|
|
154
154
|
|
|
155
|
-
Copyright 2021-
|
|
155
|
+
Copyright 2021-2024 Viam Inc.
|
|
156
156
|
|
|
157
157
|
Apache 2.0 - See [LICENSE](https://github.com/viamrobotics/viam-python-sdk/blob/main/LICENSE) file
|
|
158
|
-
|