viam-sdk 0.3.0__py3-none-linux_armv6l.whl → 0.66.0__py3-none-linux_armv6l.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.
Potentially problematic release.
This version of viam-sdk might be problematic. Click here for more details.
- viam/__init__.py +29 -2
- viam/app/_logs.py +34 -0
- viam/app/app_client.py +2696 -0
- viam/app/billing_client.py +185 -0
- viam/app/data_client.py +2231 -0
- viam/app/ml_training_client.py +249 -0
- viam/app/provisioning_client.py +93 -0
- viam/app/viam_client.py +275 -0
- viam/components/arm/__init__.py +3 -26
- viam/components/arm/arm.py +123 -8
- viam/components/arm/client.py +37 -24
- viam/components/arm/service.py +35 -32
- 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_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 +6 -11
- viam/components/base/base.py +134 -8
- viam/components/base/client.py +51 -23
- viam/components/base/service.py +33 -30
- viam/components/board/__init__.py +3 -12
- viam/components/board/board.py +247 -91
- viam/components/board/client.py +149 -83
- viam/components/board/service.py +63 -33
- 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 +3 -3
- viam/components/camera/camera.py +62 -27
- viam/components/camera/client.py +59 -27
- viam/components/camera/service.py +42 -65
- viam/components/component_base.py +28 -5
- viam/components/encoder/__init__.py +1 -1
- viam/components/encoder/client.py +25 -14
- viam/components/encoder/encoder.py +48 -10
- viam/components/encoder/service.py +14 -18
- viam/components/gantry/__init__.py +1 -13
- viam/components/gantry/client.py +80 -25
- viam/components/gantry/gantry.py +123 -9
- viam/components/gantry/service.py +51 -29
- viam/components/generic/__init__.py +1 -1
- viam/components/generic/client.py +21 -8
- viam/components/generic/generic.py +10 -2
- viam/components/generic/service.py +12 -7
- viam/components/gripper/__init__.py +3 -13
- viam/components/gripper/client.py +69 -21
- viam/components/gripper/gripper.py +123 -3
- viam/components/gripper/service.py +44 -22
- viam/components/input/__init__.py +1 -14
- viam/components/input/client.py +55 -23
- viam/components/input/input.py +106 -3
- viam/components/input/service.py +16 -21
- viam/components/motor/__init__.py +1 -21
- viam/components/motor/client.py +56 -33
- viam/components/motor/motor.py +127 -4
- viam/components/motor/service.py +33 -44
- viam/components/movement_sensor/__init__.py +1 -1
- viam/components/movement_sensor/client.py +102 -45
- viam/components/movement_sensor/movement_sensor.py +130 -61
- viam/components/movement_sensor/service.py +38 -41
- viam/components/pose_tracker/__init__.py +1 -1
- viam/components/pose_tracker/client.py +18 -7
- viam/components/pose_tracker/pose_tracker.py +4 -2
- viam/components/pose_tracker/service.py +12 -10
- viam/components/power_sensor/__init__.py +17 -0
- viam/components/power_sensor/client.py +86 -0
- viam/components/power_sensor/power_sensor.py +104 -0
- viam/components/power_sensor/service.py +72 -0
- viam/components/sensor/__init__.py +2 -1
- viam/components/sensor/client.py +26 -10
- viam/components/sensor/sensor.py +22 -4
- viam/components/sensor/service.py +20 -11
- viam/components/servo/__init__.py +1 -13
- viam/components/servo/client.py +47 -21
- viam/components/servo/service.py +15 -22
- viam/components/servo/servo.py +61 -2
- 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 +98 -0
- viam/errors.py +10 -0
- viam/gen/app/agent/v1/agent_grpc.py +29 -0
- viam/gen/app/agent/v1/agent_pb2.py +47 -0
- viam/gen/app/agent/v1/agent_pb2.pyi +280 -0
- viam/gen/app/cloudslam/v1/__init__.py +0 -0
- viam/gen/app/cloudslam/v1/cloud_slam_grpc.py +70 -0
- viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +54 -0
- viam/gen/app/cloudslam/v1/cloud_slam_pb2.pyi +384 -0
- viam/gen/app/data/v1/data_grpc.py +197 -8
- viam/gen/app/data/v1/data_pb2.py +238 -99
- viam/gen/app/data/v1/data_pb2.pyi +1222 -259
- viam/gen/app/datapipelines/__init__.py +0 -0
- viam/gen/app/datapipelines/v1/__init__.py +0 -0
- 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/__init__.py +0 -0
- viam/gen/app/dataset/v1/__init__.py +0 -0
- viam/gen/app/dataset/v1/dataset_grpc.py +68 -0
- viam/gen/app/dataset/v1/dataset_pb2.py +44 -0
- viam/gen/app/dataset/v1/dataset_pb2.pyi +214 -0
- viam/gen/app/datasync/v1/data_sync_grpc.py +21 -4
- viam/gen/app/datasync/v1/data_sync_pb2.py +62 -128
- viam/gen/app/datasync/v1/data_sync_pb2.pyi +156 -199
- 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 +51 -3
- viam/gen/app/mltraining/v1/ml_training_pb2.py +135 -58
- viam/gen/app/mltraining/v1/ml_training_pb2.pyi +328 -39
- viam/gen/app/packages/v1/packages_grpc.py +15 -1
- viam/gen/app/packages/v1/packages_pb2.py +44 -64
- viam/gen/app/packages/v1/packages_pb2.pyi +75 -85
- viam/gen/app/v1/app_grpc.py +644 -3
- viam/gen/app/v1/app_pb2.py +695 -295
- viam/gen/app/v1/app_pb2.pyi +4488 -635
- viam/gen/app/v1/billing_grpc.py +53 -11
- viam/gen/app/v1/billing_pb2.py +94 -39
- viam/gen/app/v1/billing_pb2.pyi +391 -191
- viam/gen/app/v1/end_user_grpc.py +59 -0
- viam/gen/app/v1/end_user_pb2.py +55 -0
- viam/gen/app/v1/end_user_pb2.pyi +181 -0
- viam/gen/app/v1/robot_grpc.py +16 -1
- viam/gen/app/v1/robot_pb2.py +122 -94
- viam/gen/app/v1/robot_pb2.pyi +463 -123
- viam/gen/common/v1/common_pb2.py +87 -58
- viam/gen/common/v1/common_pb2.pyi +456 -149
- viam/gen/component/arm/v1/arm_grpc.py +58 -2
- viam/gen/component/arm/v1/arm_pb2.py +68 -51
- viam/gen/component/arm/v1/arm_pb2.pyi +108 -42
- 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_grpc.py +25 -2
- viam/gen/component/audioinput/v1/audioinput_pb2.py +36 -31
- viam/gen/component/audioinput/v1/audioinput_pb2.pyi +22 -22
- 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_grpc.py +42 -2
- viam/gen/component/base/v1/base_pb2.py +58 -47
- viam/gen/component/base/v1/base_pb2.pyi +65 -30
- viam/gen/component/board/v1/board_grpc.py +59 -7
- viam/gen/component/board/v1/board_pb2.py +94 -73
- viam/gen/component/board/v1/board_pb2.pyi +165 -68
- 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_grpc.py +38 -2
- viam/gen/component/camera/v1/camera_pb2.py +60 -43
- viam/gen/component/camera/v1/camera_pb2.pyi +191 -37
- viam/gen/component/encoder/v1/encoder_grpc.py +25 -2
- viam/gen/component/encoder/v1/encoder_pb2.py +36 -31
- viam/gen/component/encoder/v1/encoder_pb2.pyi +15 -15
- viam/gen/component/gantry/v1/gantry_grpc.py +47 -2
- viam/gen/component/gantry/v1/gantry_pb2.py +56 -43
- viam/gen/component/gantry/v1/gantry_pb2.pyi +67 -31
- viam/gen/component/generic/v1/generic_grpc.py +16 -2
- viam/gen/component/generic/v1/generic_pb2.py +16 -11
- viam/gen/component/gripper/v1/gripper_grpc.py +44 -2
- viam/gen/component/gripper/v1/gripper_pb2.py +48 -35
- viam/gen/component/gripper/v1/gripper_pb2.pyi +62 -24
- viam/gen/component/inputcontroller/v1/input_controller_grpc.py +28 -2
- viam/gen/component/inputcontroller/v1/input_controller_pb2.py +46 -41
- viam/gen/component/inputcontroller/v1/input_controller_pb2.pyi +32 -36
- viam/gen/component/motor/v1/motor_grpc.py +51 -2
- viam/gen/component/motor/v1/motor_pb2.py +78 -67
- viam/gen/component/motor/v1/motor_pb2.pyi +75 -46
- viam/gen/component/movementsensor/v1/movementsensor_grpc.py +48 -2
- viam/gen/component/movementsensor/v1/movementsensor_pb2.py +70 -63
- viam/gen/component/movementsensor/v1/movementsensor_pb2.pyi +84 -57
- viam/gen/component/posetracker/v1/pose_tracker_grpc.py +19 -2
- viam/gen/component/posetracker/v1/pose_tracker_pb2.py +26 -21
- viam/gen/component/posetracker/v1/pose_tracker_pb2.pyi +9 -13
- viam/gen/component/powersensor/__init__.py +0 -0
- viam/gen/component/powersensor/v1/__init__.py +0 -0
- viam/gen/component/powersensor/v1/powersensor_grpc.py +62 -0
- viam/gen/component/powersensor/v1/powersensor_pb2.py +42 -0
- viam/gen/component/powersensor/v1/powersensor_pb2.pyi +124 -0
- viam/gen/component/sensor/v1/sensor_grpc.py +21 -5
- viam/gen/component/sensor/v1/sensor_pb2.py +18 -22
- viam/gen/component/sensor/v1/sensor_pb2.pyi +1 -69
- viam/gen/component/servo/v1/servo_grpc.py +28 -2
- viam/gen/component/servo/v1/servo_pb2.py +42 -37
- viam/gen/component/servo/v1/servo_pb2.pyi +22 -26
- 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_grpc.py +15 -0
- viam/gen/component/testecho/v1/testecho_pb2.py +29 -26
- viam/gen/component/testecho/v1/testecho_pb2.pyi +16 -20
- viam/gen/module/v1/module_grpc.py +18 -0
- viam/gen/module/v1/module_pb2.py +36 -33
- viam/gen/module/v1/module_pb2.pyi +39 -34
- viam/gen/opentelemetry/__init__.py +0 -0
- viam/gen/opentelemetry/proto/__init__.py +0 -0
- viam/gen/opentelemetry/proto/common/__init__.py +0 -0
- viam/gen/opentelemetry/proto/common/v1/__init__.py +0 -0
- viam/gen/opentelemetry/proto/common/v1/common_grpc.py +0 -0
- viam/gen/opentelemetry/proto/common/v1/common_pb2.py +27 -0
- viam/gen/opentelemetry/proto/common/v1/common_pb2.pyi +208 -0
- viam/gen/opentelemetry/proto/resource/__init__.py +0 -0
- viam/gen/opentelemetry/proto/resource/v1/__init__.py +0 -0
- viam/gen/opentelemetry/proto/resource/v1/resource_grpc.py +0 -0
- viam/gen/opentelemetry/proto/resource/v1/resource_pb2.py +18 -0
- viam/gen/opentelemetry/proto/resource/v1/resource_pb2.pyi +59 -0
- viam/gen/opentelemetry/proto/trace/__init__.py +0 -0
- viam/gen/opentelemetry/proto/trace/v1/__init__.py +0 -0
- viam/gen/opentelemetry/proto/trace/v1/trace_grpc.py +0 -0
- viam/gen/opentelemetry/proto/trace/v1/trace_pb2.py +37 -0
- viam/gen/opentelemetry/proto/trace/v1/trace_pb2.pyi +402 -0
- viam/gen/proto/rpc/examples/echo/v1/echo_grpc.py +12 -0
- viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +25 -22
- viam/gen/proto/rpc/examples/echo/v1/echo_pb2.pyi +13 -17
- viam/gen/proto/rpc/examples/echoresource/v1/echoresource_grpc.py +12 -0
- viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +23 -20
- viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.pyi +13 -17
- viam/gen/proto/rpc/v1/auth_grpc.py +11 -0
- viam/gen/proto/rpc/v1/auth_pb2.py +27 -24
- viam/gen/proto/rpc/v1/auth_pb2.pyi +12 -16
- viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +35 -32
- viam/gen/proto/rpc/webrtc/v1/grpc_pb2.pyi +37 -41
- viam/gen/proto/rpc/webrtc/v1/signaling_grpc.py +15 -0
- viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +62 -57
- viam/gen/proto/rpc/webrtc/v1/signaling_pb2.pyi +78 -69
- viam/gen/provisioning/__init__.py +0 -0
- viam/gen/provisioning/v1/__init__.py +0 -0
- viam/gen/provisioning/v1/provisioning_grpc.py +59 -0
- viam/gen/provisioning/v1/provisioning_pb2.py +45 -0
- viam/gen/provisioning/v1/provisioning_pb2.pyi +229 -0
- viam/gen/robot/v1/robot_grpc.py +144 -15
- viam/gen/robot/v1/robot_pb2.py +193 -119
- viam/gen/robot/v1/robot_pb2.pyi +565 -137
- viam/gen/service/datamanager/v1/data_manager_grpc.py +20 -2
- viam/gen/service/datamanager/v1/data_manager_pb2.py +27 -17
- viam/gen/service/datamanager/v1/data_manager_pb2.pyi +52 -10
- 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/__init__.py +0 -0
- viam/gen/service/generic/v1/__init__.py +0 -0
- viam/gen/service/generic/v1/generic_grpc.py +29 -0
- viam/gen/service/generic/v1/generic_pb2.py +21 -0
- viam/gen/service/generic/v1/generic_pb2.pyi +6 -0
- viam/gen/service/mlmodel/v1/mlmodel_grpc.py +9 -0
- viam/gen/service/mlmodel/v1/mlmodel_pb2.py +76 -29
- viam/gen/service/mlmodel/v1/mlmodel_pb2.pyi +307 -28
- viam/gen/service/motion/v1/motion_grpc.py +42 -4
- viam/gen/service/motion/v1/motion_pb2.py +119 -51
- viam/gen/service/motion/v1/motion_pb2.pyi +595 -120
- viam/gen/service/navigation/v1/navigation_grpc.py +49 -1
- viam/gen/service/navigation/v1/navigation_pb2.py +76 -51
- viam/gen/service/navigation/v1/navigation_pb2.pyi +188 -33
- viam/gen/service/sensors/v1/sensors_grpc.py +12 -0
- viam/gen/service/sensors/v1/sensors_pb2.py +60 -29
- viam/gen/service/sensors/v1/sensors_pb2.pyi +18 -21
- viam/gen/service/shell/v1/shell_grpc.py +27 -1
- viam/gen/service/shell/v1/shell_pb2.py +37 -15
- viam/gen/service/shell/v1/shell_pb2.pyi +260 -7
- viam/gen/service/slam/v1/slam_grpc.py +24 -2
- viam/gen/service/slam/v1/slam_pb2.py +44 -30
- viam/gen/service/slam/v1/slam_pb2.pyi +128 -27
- 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_grpc.py +39 -1
- viam/gen/service/vision/v1/vision_pb2.py +61 -45
- viam/gen/service/vision/v1/vision_pb2.pyi +180 -41
- 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/__init__.py +0 -0
- viam/gen/stream/v1/__init__.py +0 -0
- viam/gen/stream/v1/stream_grpc.py +59 -0
- viam/gen/stream/v1/stream_pb2.py +39 -0
- viam/gen/stream/v1/stream_pb2.pyi +161 -0
- viam/gen/tagger/v1/tagger_pb2.py +9 -8
- viam/logging.py +160 -17
- viam/media/__init__.py +0 -9
- viam/media/audio.py +22 -10
- viam/media/utils/__init__.py +0 -0
- viam/media/utils/pil/__init__.py +55 -0
- viam/media/{viam_rgba_plugin.py → utils/pil/viam_rgba_plugin.py} +10 -16
- viam/media/viam_rgba.py +10 -0
- viam/media/video.py +197 -73
- viam/module/module.py +191 -44
- viam/module/resource_data_consumer.py +41 -0
- viam/module/service.py +9 -1
- viam/module/types.py +4 -5
- viam/operations.py +4 -3
- viam/proto/app/__init__.py +361 -5
- viam/proto/app/agent/__init__.py +28 -0
- viam/proto/app/billing.py +51 -27
- viam/proto/app/cloudslam/__init__.py +48 -0
- viam/proto/app/data/__init__.py +103 -17
- viam/proto/app/datapipelines/__init__.py +56 -0
- viam/proto/app/dataset/__init__.py +40 -0
- viam/proto/app/datasync/__init__.py +11 -5
- viam/proto/app/end_user.py +34 -0
- viam/proto/app/mlinference/__init__.py +15 -0
- viam/proto/app/mltraining/__init__.py +25 -1
- viam/proto/app/packages/__init__.py +3 -3
- viam/proto/app/robot.py +19 -1
- viam/proto/common/__init__.py +35 -8
- viam/proto/component/arm/__init__.py +9 -1
- viam/proto/component/audioin/__init__.py +16 -0
- viam/proto/component/audioinput/__init__.py +3 -1
- viam/proto/component/audioout/__init__.py +15 -0
- viam/proto/component/base/__init__.py +7 -1
- viam/proto/component/board/__init__.py +13 -5
- viam/proto/component/button/__init__.py +15 -0
- viam/proto/component/camera/__init__.py +9 -1
- viam/proto/component/encoder/__init__.py +3 -1
- viam/proto/component/gantry/__init__.py +7 -1
- viam/proto/component/generic/__init__.py +3 -1
- viam/proto/component/gripper/__init__.py +7 -1
- viam/proto/component/inputcontroller/__init__.py +7 -1
- viam/proto/component/motor/__init__.py +7 -1
- viam/proto/component/movementsensor/__init__.py +7 -1
- viam/proto/component/posetracker/__init__.py +7 -1
- viam/proto/component/powersensor/__init__.py +30 -0
- viam/proto/component/sensor/__init__.py +3 -4
- viam/proto/component/servo/__init__.py +3 -1
- viam/proto/component/switch/__init__.py +26 -0
- viam/proto/component/testecho/__init__.py +3 -1
- viam/proto/module/__init__.py +3 -1
- viam/proto/opentelemetry/__init__.py +0 -0
- viam/proto/opentelemetry/proto/__init__.py +0 -0
- viam/proto/opentelemetry/proto/common/__init__.py +15 -0
- viam/proto/opentelemetry/proto/resource/__init__.py +10 -0
- viam/proto/opentelemetry/proto/trace/__init__.py +15 -0
- viam/proto/provisioning/__init__.py +42 -0
- viam/proto/robot/__init__.py +57 -9
- viam/proto/rpc/auth.py +11 -1
- viam/proto/rpc/examples/echo/__init__.py +3 -1
- viam/proto/rpc/examples/echoresource/__init__.py +7 -1
- viam/proto/rpc/webrtc/grpc.py +3 -1
- viam/proto/rpc/webrtc/signaling.py +5 -1
- viam/proto/service/datamanager/__init__.py +15 -2
- viam/proto/service/discovery/__init__.py +15 -0
- viam/proto/service/generic/__init__.py +12 -0
- viam/proto/service/mlmodel/__init__.py +27 -1
- viam/proto/service/motion/__init__.py +35 -5
- viam/proto/service/navigation/__init__.py +19 -1
- viam/proto/service/sensors/__init__.py +3 -1
- viam/proto/service/shell/__init__.py +25 -2
- viam/proto/service/slam/__init__.py +13 -1
- viam/proto/service/video/__init__.py +15 -0
- viam/proto/service/vision/__init__.py +11 -1
- viam/proto/service/worldstatestore/__init__.py +32 -0
- viam/proto/stream/__init__.py +36 -0
- viam/py.typed +0 -0
- viam/resource/base.py +45 -8
- viam/resource/easy_resource.py +149 -0
- viam/resource/manager.py +35 -14
- viam/resource/registry.py +40 -52
- viam/resource/rpc_client_base.py +33 -1
- viam/resource/rpc_service_base.py +15 -8
- viam/resource/types.py +39 -26
- viam/robot/client.py +458 -91
- viam/robot/service.py +13 -107
- viam/rpc/dial.py +133 -15
- viam/rpc/libviam_rust_utils.so +0 -0
- viam/rpc/server.py +59 -15
- 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 +18 -0
- viam/services/generic/client.py +58 -0
- viam/services/generic/generic.py +58 -0
- viam/services/generic/service.py +29 -0
- viam/services/mlmodel/__init__.py +15 -1
- viam/services/mlmodel/client.py +20 -15
- viam/services/mlmodel/mlmodel.py +44 -7
- viam/services/mlmodel/service.py +9 -13
- viam/services/mlmodel/utils.py +101 -0
- viam/services/motion/__init__.py +15 -3
- viam/services/motion/client.py +109 -150
- viam/services/motion/motion.py +380 -0
- viam/services/motion/service.py +132 -0
- viam/services/navigation/__init__.py +11 -0
- viam/services/navigation/client.py +99 -0
- viam/services/navigation/navigation.py +250 -0
- viam/services/navigation/service.py +137 -0
- viam/services/service_base.py +43 -4
- viam/services/service_client_base.py +4 -4
- viam/services/slam/__init__.py +4 -1
- viam/services/slam/client.py +21 -11
- viam/services/slam/service.py +16 -19
- viam/services/slam/slam.py +66 -5
- viam/services/vision/__init__.py +8 -0
- viam/services/vision/client.py +115 -111
- viam/services/vision/service.py +143 -0
- viam/services/vision/vision.py +317 -0
- 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 +254 -0
- viam/streams.py +44 -0
- viam/utils.py +143 -15
- viam/version_metadata.py +4 -0
- viam_sdk-0.66.0.dist-info/METADATA +157 -0
- viam_sdk-0.66.0.dist-info/RECORD +531 -0
- {viam_sdk-0.3.0.dist-info → viam_sdk-0.66.0.dist-info}/WHEEL +1 -1
- viam/components/audio_input/__init__.py +0 -18
- viam/components/audio_input/audio_input.py +0 -79
- viam/components/audio_input/client.py +0 -60
- viam/components/audio_input/service.py +0 -118
- viam/components/types.py +0 -5
- viam/gen/app/model/v1/model_grpc.py +0 -39
- viam/gen/app/model/v1/model_pb2.py +0 -71
- viam/gen/app/model/v1/model_pb2.pyi +0 -285
- viam/gen/proto/rpc/examples/fileupload/v1/fileupload_grpc.py +0 -21
- viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.py +0 -18
- viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.pyi +0 -49
- viam/media/media.py +0 -53
- viam/proto/app/model/__init__.py +0 -40
- viam/proto/rpc/examples/fileupload/__init__.py +0 -13
- viam/services/sensors/__init__.py +0 -5
- viam/services/sensors/client.py +0 -63
- viam_sdk-0.3.0.dist-info/LICENSE +0 -202
- viam_sdk-0.3.0.dist-info/METADATA +0 -122
- viam_sdk-0.3.0.dist-info/RECORD +0 -372
- /viam/{gen/app/model → app}/__init__.py +0 -0
- /viam/gen/app/{model/v1 → agent}/__init__.py +0 -0
- /viam/gen/{proto/rpc/examples/fileupload → app/agent/v1}/__init__.py +0 -0
- /viam/gen/{proto/rpc/examples/fileupload/v1 → app/cloudslam}/__init__.py +0 -0
- /LICENSE → /viam_sdk-0.66.0.dist-info/licenses/LICENSE +0 -0
viam/media/video.py
CHANGED
|
@@ -1,107 +1,231 @@
|
|
|
1
1
|
from array import array
|
|
2
|
-
from
|
|
3
|
-
from io import BytesIO
|
|
4
|
-
from typing import List, NamedTuple, Tuple, Union
|
|
2
|
+
from typing import Any, List, Optional, Tuple
|
|
5
3
|
|
|
6
|
-
from
|
|
7
|
-
from typing_extensions import Self
|
|
4
|
+
from typing_extensions import ClassVar, Self
|
|
8
5
|
|
|
9
6
|
from viam.errors import NotSupportedError
|
|
10
7
|
|
|
11
|
-
from .
|
|
8
|
+
from .viam_rgba import RGBA_HEADER_LENGTH, RGBA_MAGIC_NUMBER
|
|
12
9
|
|
|
13
|
-
LAZY_SUFFIX = "+lazy"
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
class _FrozenClassAttributesMeta(type):
|
|
12
|
+
"""
|
|
13
|
+
A metaclass that prevents the reassignment of existing class attributes.
|
|
14
|
+
"""
|
|
17
15
|
|
|
16
|
+
def __setattr__(cls, name: str, value: Any):
|
|
17
|
+
# Check if the attribute `name` already exists on the class
|
|
18
|
+
if name in cls.__dict__:
|
|
19
|
+
# If it exists, raise an error to prevent overwriting
|
|
20
|
+
raise AttributeError(f"Cannot reassign constant '{name}'")
|
|
21
|
+
# If it's a new attribute, allow it to be set
|
|
22
|
+
super().__setattr__(name, value)
|
|
18
23
|
|
|
19
|
-
class RawImage(NamedTuple):
|
|
20
|
-
"""A raw bytes representation of an image.
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
class CameraMimeType(str, metaclass=_FrozenClassAttributesMeta):
|
|
26
|
+
"""
|
|
27
|
+
The compatible mime-types for cameras and vision services.
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
2) The requested mime type is not supported for decoding/encoding by Viam's
|
|
27
|
-
Python SDK
|
|
29
|
+
You can use the `CameraMimeType.CUSTOM(...)` method to use an unlisted mime-type.
|
|
28
30
|
"""
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
VIAM_RGBA: ClassVar[Self]
|
|
33
|
+
VIAM_RAW_DEPTH: ClassVar[Self]
|
|
34
|
+
JPEG: ClassVar[Self]
|
|
35
|
+
PNG: ClassVar[Self]
|
|
36
|
+
PCD: ClassVar[Self]
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
@property
|
|
39
|
+
def name(self) -> str:
|
|
40
|
+
for key, value in self.__class__.__dict__.items():
|
|
41
|
+
if value == self:
|
|
42
|
+
return key
|
|
43
|
+
return "CUSTOM"
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
45
|
+
@property
|
|
46
|
+
def value(self) -> str:
|
|
47
|
+
return self
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
@classmethod
|
|
50
|
+
def CUSTOM(cls, mime_type: str) -> Self:
|
|
51
|
+
"""
|
|
52
|
+
Create a custom mime type.
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
Args:
|
|
55
|
+
mime_type (str): The mimetype as a string
|
|
56
|
+
"""
|
|
57
|
+
return cls.from_string(mime_type)
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_string(cls, value: str) -> Self:
|
|
61
|
+
"""Return the mimetype from a string.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
value (str): The mimetype as a string
|
|
46
65
|
|
|
47
66
|
Returns:
|
|
48
|
-
|
|
67
|
+
Self: The mimetype
|
|
49
68
|
"""
|
|
50
|
-
if
|
|
51
|
-
|
|
69
|
+
value_mime = value[:-5] if value.endswith("+lazy") else value # ViamImage lazy encodes by default
|
|
70
|
+
return cls(value_mime)
|
|
52
71
|
|
|
53
|
-
width = int.from_bytes(self.data[8:16], "big")
|
|
54
|
-
height = int.from_bytes(self.data[16:24], "big")
|
|
55
|
-
depth_arr = array("H", self.data[24:])
|
|
56
|
-
depth_arr.byteswap()
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
CameraMimeType.VIAM_RGBA = CameraMimeType.from_string("image/vnd.viam.rgba")
|
|
74
|
+
CameraMimeType.VIAM_RAW_DEPTH = CameraMimeType.from_string("image/vnd.viam.dep")
|
|
75
|
+
CameraMimeType.JPEG = CameraMimeType.from_string("image/jpeg")
|
|
76
|
+
CameraMimeType.PNG = CameraMimeType.from_string("image/png")
|
|
77
|
+
CameraMimeType.PCD = CameraMimeType.from_string("pointcloud/pcd")
|
|
60
78
|
|
|
61
79
|
|
|
62
|
-
class
|
|
63
|
-
|
|
64
|
-
JPEG = "image/jpeg"
|
|
65
|
-
PNG = "image/png"
|
|
66
|
-
PCD = "pointcloud/pcd"
|
|
67
|
-
UNSUPPORTED = "unsupported"
|
|
80
|
+
class ViamImage:
|
|
81
|
+
"""A native implementation of an image.
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
Provides the raw data and the mime type.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
_data: bytes
|
|
87
|
+
_mime_type: CameraMimeType
|
|
88
|
+
_height: Optional[int] = None
|
|
89
|
+
_width: Optional[int] = None
|
|
90
|
+
|
|
91
|
+
def __init__(self, data: bytes, mime_type: CameraMimeType) -> None:
|
|
92
|
+
self._data = data
|
|
93
|
+
self._mime_type = mime_type
|
|
94
|
+
self._width, self._height = _getDimensions(data, mime_type)
|
|
79
95
|
|
|
80
96
|
@property
|
|
81
|
-
def
|
|
82
|
-
|
|
97
|
+
def data(self) -> bytes:
|
|
98
|
+
"""The raw bytes of the image"""
|
|
99
|
+
return self._data
|
|
83
100
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
101
|
+
@property
|
|
102
|
+
def mime_type(self) -> CameraMimeType:
|
|
103
|
+
"""The mime type of the image"""
|
|
104
|
+
return self._mime_type
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
else:
|
|
93
|
-
raise ValueError(f"Cannot encode image to {self}")
|
|
106
|
+
@property
|
|
107
|
+
def width(self) -> Optional[int]:
|
|
108
|
+
"""The width of the image"""
|
|
109
|
+
return self._width
|
|
94
110
|
|
|
95
|
-
@
|
|
96
|
-
def
|
|
97
|
-
"""
|
|
111
|
+
@property
|
|
112
|
+
def height(self) -> Optional[int]:
|
|
113
|
+
"""The height of the image"""
|
|
114
|
+
return self._height
|
|
98
115
|
|
|
99
|
-
|
|
100
|
-
|
|
116
|
+
def bytes_to_depth_array(self) -> List[List[int]]:
|
|
117
|
+
"""
|
|
118
|
+
Decode the data of an image that has the custom depth MIME type ``image/vnd.viam.dep`` into a standard representation.
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
NotSupportedError: Raised if the image is not of MIME type `image/vnd.viam.dep`.
|
|
101
122
|
|
|
102
123
|
Returns:
|
|
103
|
-
|
|
124
|
+
List[List[int]]: The standard representation of the image.
|
|
104
125
|
"""
|
|
105
|
-
if mime_type
|
|
106
|
-
|
|
107
|
-
|
|
126
|
+
if self.mime_type != CameraMimeType.VIAM_RAW_DEPTH:
|
|
127
|
+
raise NotSupportedError("Type must be `image/vnd.viam.dep` to use bytes_to_depth_array()")
|
|
128
|
+
|
|
129
|
+
self._width = int.from_bytes(self.data[8:16], "big")
|
|
130
|
+
self._height = int.from_bytes(self.data[16:24], "big")
|
|
131
|
+
depth_arr = array("H", self.data[24:])
|
|
132
|
+
depth_arr.byteswap()
|
|
133
|
+
|
|
134
|
+
depth_arr_2d = [[depth_arr[row * self._width + col] for col in range(self._width)] for row in range(self._height)]
|
|
135
|
+
return depth_arr_2d
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class NamedImage(ViamImage):
|
|
139
|
+
"""An implementation of ViamImage that contains a name attribute."""
|
|
140
|
+
|
|
141
|
+
name: str
|
|
142
|
+
"""The name of the image
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
def __init__(self, name: str, data: bytes, mime_type: CameraMimeType) -> None:
|
|
146
|
+
self.name = name
|
|
147
|
+
super().__init__(data, mime_type)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _getDimensions(image: bytes, mime_type: CameraMimeType) -> Tuple[Optional[int], Optional[int]]:
|
|
151
|
+
try:
|
|
152
|
+
if mime_type == CameraMimeType.JPEG:
|
|
153
|
+
return _getDimensionsFromJPEG(image)
|
|
154
|
+
if mime_type == CameraMimeType.PNG:
|
|
155
|
+
return _getDimensionsFromPNG(image)
|
|
156
|
+
if mime_type == CameraMimeType.VIAM_RGBA:
|
|
157
|
+
return _getDimensionsFromRGBA(image)
|
|
158
|
+
except ValueError:
|
|
159
|
+
return (None, None)
|
|
160
|
+
return (None, None)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _getDimensionsFromJPEG(image: bytes) -> Tuple[int, int]:
|
|
164
|
+
# JPEG Specification: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
|
|
165
|
+
# Specification for markers: Table B.1
|
|
166
|
+
|
|
167
|
+
offset = 0
|
|
168
|
+
while offset < len(image):
|
|
169
|
+
while image[offset] == 0xFF:
|
|
170
|
+
# Skip all 0xFF bytes
|
|
171
|
+
offset += 1
|
|
172
|
+
|
|
173
|
+
marker = image[offset]
|
|
174
|
+
offset += 1
|
|
175
|
+
if marker == 0x01:
|
|
176
|
+
# Temporary/private use marker
|
|
177
|
+
offset += 1
|
|
178
|
+
continue
|
|
179
|
+
if marker in range(0xD0, 0xD7):
|
|
180
|
+
# Restart (RST) marker
|
|
181
|
+
offset += 1
|
|
182
|
+
continue
|
|
183
|
+
if marker == 0xD8:
|
|
184
|
+
# Start of image (SOI) marker
|
|
185
|
+
offset += 1
|
|
186
|
+
continue
|
|
187
|
+
if marker == 0xD9:
|
|
188
|
+
# End of image (EOI) marker
|
|
189
|
+
break
|
|
190
|
+
|
|
191
|
+
length = int.from_bytes(image[offset : offset + 1], byteorder="big") # length of section
|
|
192
|
+
if marker == 0xC0 or marker == 0xC2:
|
|
193
|
+
height = int.from_bytes(image[offset + 3 : offset + 5], byteorder="big")
|
|
194
|
+
width = int.from_bytes(image[offset + 5 : offset + 7], byteorder="big")
|
|
195
|
+
return (width, height)
|
|
196
|
+
|
|
197
|
+
offset += length
|
|
198
|
+
|
|
199
|
+
raise ValueError("Invalid JPEG: Could not extract dimensions")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _getDimensionsFromPNG(image: bytes) -> Tuple[int, int]:
|
|
203
|
+
# PNG Specification: https://www.w3.org/TR/png/
|
|
204
|
+
|
|
205
|
+
# PNG will always start with this signature
|
|
206
|
+
signature = image[:8]
|
|
207
|
+
if signature != [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]:
|
|
208
|
+
ValueError("Invalid PNG: Invalid signature")
|
|
209
|
+
|
|
210
|
+
header = image[12:24]
|
|
211
|
+
chunk_type = header[:4].decode()
|
|
212
|
+
if chunk_type != "IHDR":
|
|
213
|
+
ValueError("Invalid PNG: Invalid headers")
|
|
214
|
+
|
|
215
|
+
width = int.from_bytes(header[4:8], byteorder="big")
|
|
216
|
+
height = int.from_bytes(header[8:], byteorder="big")
|
|
217
|
+
return (width, height)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _getDimensionsFromRGBA(image: bytes) -> Tuple[int, int]:
|
|
221
|
+
# Viam RGBA header comes in 3 4-byte chunks:
|
|
222
|
+
# * Magic Number/Signature
|
|
223
|
+
# * Width
|
|
224
|
+
# * Height
|
|
225
|
+
header = image[:RGBA_HEADER_LENGTH]
|
|
226
|
+
if header[:4] != RGBA_MAGIC_NUMBER:
|
|
227
|
+
raise ValueError("Invalid Viam RGBA: Invalid headers")
|
|
228
|
+
|
|
229
|
+
width = int.from_bytes(header[4:8], byteorder="big")
|
|
230
|
+
height = int.from_bytes(header[8:], byteorder="big")
|
|
231
|
+
return (width, height)
|
viam/module/module.py
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import io
|
|
3
|
+
import logging as pylogging
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from collections.abc import Iterable
|
|
1
7
|
from inspect import iscoroutinefunction
|
|
2
8
|
from threading import Lock
|
|
3
9
|
from typing import List, Mapping, Optional, Sequence, Tuple
|
|
4
10
|
|
|
11
|
+
from grpclib.metadata import Deadline
|
|
5
12
|
from grpclib.utils import _service_name
|
|
13
|
+
from typing_extensions import Self
|
|
6
14
|
|
|
7
15
|
from viam import logging
|
|
8
|
-
from viam.components.component_base import ComponentBase
|
|
9
16
|
from viam.errors import ResourceNotFoundError, ValidationError
|
|
17
|
+
from viam.logging import update_log_level
|
|
10
18
|
from viam.proto.app.robot import ComponentConfig
|
|
11
19
|
from viam.proto.module import (
|
|
12
20
|
AddResourceRequest,
|
|
@@ -22,15 +30,50 @@ from viam.proto.module import (
|
|
|
22
30
|
from viam.proto.robot import ResourceRPCSubtype
|
|
23
31
|
from viam.resource.base import ResourceBase
|
|
24
32
|
from viam.resource.registry import Registry
|
|
25
|
-
from viam.resource.types import Model, ResourceName,
|
|
33
|
+
from viam.resource.types import API, RESOURCE_TYPE_COMPONENT, RESOURCE_TYPE_SERVICE, Model, ResourceName, resource_name_from_string
|
|
26
34
|
from viam.robot.client import RobotClient
|
|
27
|
-
from viam.rpc.dial import DialOptions
|
|
35
|
+
from viam.rpc.dial import DialOptions, _host_port_from_url
|
|
28
36
|
from viam.rpc.server import Server
|
|
29
37
|
|
|
38
|
+
# These imports are required to register built-in resources with the registry
|
|
39
|
+
from ..components.arm import Arm # noqa: F401
|
|
40
|
+
from ..components.base import Base # noqa: F401
|
|
41
|
+
from ..components.board import Board # noqa: F401
|
|
42
|
+
from ..components.button import Button # noqa: F401
|
|
43
|
+
from ..components.camera import Camera # noqa: F401
|
|
44
|
+
from ..components.encoder import Encoder # noqa: F401
|
|
45
|
+
from ..components.gantry import Gantry # noqa: F401
|
|
46
|
+
from ..components.generic import Generic as GenericComponent # noqa: F401
|
|
47
|
+
from ..components.gripper import Gripper # noqa: F401
|
|
48
|
+
from ..components.input import Controller # noqa: F401
|
|
49
|
+
from ..components.motor import Motor # noqa: F401
|
|
50
|
+
from ..components.movement_sensor import MovementSensor # noqa: F401
|
|
51
|
+
from ..components.pose_tracker import PoseTracker # noqa: F401
|
|
52
|
+
from ..components.power_sensor import PowerSensor # noqa: F401
|
|
53
|
+
from ..components.sensor import Sensor # noqa: F401
|
|
54
|
+
from ..components.servo import Servo # noqa: F401
|
|
55
|
+
from ..components.switch import Switch # noqa: F401
|
|
56
|
+
from ..services.discovery import Discovery # noqa: F401
|
|
57
|
+
from ..services.generic import Generic as GenericService # noqa: F401
|
|
58
|
+
from ..services.motion import Motion # noqa: F401
|
|
59
|
+
from ..services.navigation import Navigation # noqa: F401
|
|
60
|
+
from ..services.slam import SLAM # noqa: F401
|
|
61
|
+
from ..services.vision import Vision # noqa: F401
|
|
30
62
|
from .service import ModuleRPCService
|
|
31
63
|
from .types import Reconfigurable, Stoppable
|
|
32
64
|
|
|
33
|
-
|
|
65
|
+
NO_MODULE_PARENT = os.environ.get("VIAM_NO_MODULE_PARENT", "").lower() == "true"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _parse_module_args() -> argparse.Namespace:
|
|
69
|
+
"""
|
|
70
|
+
Parse command-line args. Used by the various `Module` entrypoints.
|
|
71
|
+
"""
|
|
72
|
+
p = argparse.ArgumentParser(description="Start this viam python module")
|
|
73
|
+
p.add_argument("socket_path", help="path where this module will serve a unix socket")
|
|
74
|
+
p.add_argument("--log-level", type=lambda name: pylogging._nameToLevel[name.upper()], default=logging.INFO)
|
|
75
|
+
p.add_argument("--tcp-mode", action="store_true")
|
|
76
|
+
return p.parse_known_args()[0]
|
|
34
77
|
|
|
35
78
|
|
|
36
79
|
class Module:
|
|
@@ -39,17 +82,83 @@ class Module:
|
|
|
39
82
|
_ready: bool
|
|
40
83
|
_log_level: int
|
|
41
84
|
_lock: Lock
|
|
85
|
+
_tcp_mode: bool
|
|
42
86
|
parent: Optional[RobotClient] = None
|
|
43
87
|
server: Server
|
|
88
|
+
logger: pylogging.Logger
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def from_args(cls) -> Self:
|
|
92
|
+
"""Create a new Module with the args provided in the command line. The first argument after the command must be
|
|
93
|
+
the socket path. If the second argument after the command is "--log-level=debug", the Module's logger will be
|
|
94
|
+
DEBUG level. Otherwise, it will be INFO level. See LogLevel documentation in the RDK for more information on how
|
|
95
|
+
to start modules with a "log-level" commandline argument.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
Exception: If there is no socket path provided in the command line argument
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Module: a new Module instance
|
|
102
|
+
"""
|
|
103
|
+
args = _parse_module_args()
|
|
104
|
+
return cls(args.socket_path, log_level=args.log_level, tcp_mode=args.tcp_mode)
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
async def run_with_models(cls, *models: ResourceBase):
|
|
108
|
+
"""
|
|
109
|
+
Module entrypoint that takes a list of ResourceBase implementations.
|
|
110
|
+
In most cases you'll want to use run_from_registry instead (see below).
|
|
111
|
+
"""
|
|
112
|
+
module = cls.from_args()
|
|
113
|
+
for model in models:
|
|
114
|
+
if not hasattr(model, "MODEL"):
|
|
115
|
+
raise TypeError(f"missing MODEL field on {model}. Resource implementations must define MODEL")
|
|
116
|
+
module.add_model_from_registry(model.API, model.MODEL) # pyright: ignore [reportAttributeAccessIssue]
|
|
117
|
+
await module.start()
|
|
118
|
+
|
|
119
|
+
@classmethod
|
|
120
|
+
async def run_from_registry(cls):
|
|
121
|
+
"""
|
|
122
|
+
Module entrypoint that automatically includes all the resources you've created in your program.
|
|
123
|
+
|
|
124
|
+
Example:
|
|
125
|
+
|
|
126
|
+
if __name__ == '__main__':
|
|
127
|
+
asyncio.run(Module.run_from_registry())
|
|
44
128
|
|
|
45
|
-
|
|
129
|
+
Full example at examples/easy_resource/main.py.
|
|
130
|
+
"""
|
|
131
|
+
module = cls.from_args()
|
|
132
|
+
for key in Registry.REGISTERED_RESOURCE_CREATORS().keys():
|
|
133
|
+
module.add_model_from_registry(*key.split("/")) # pyright: ignore [reportArgumentType]
|
|
134
|
+
await module.start()
|
|
135
|
+
|
|
136
|
+
def __init__(self, address: str, *, log_level: int = logging.INFO, tcp_mode: bool = False) -> None:
|
|
137
|
+
# When a module is launched by viam-server, its stdout is not connected to a tty. In
|
|
138
|
+
# response, python disables line buffering, which prevents `print` statements from being
|
|
139
|
+
# immediately flushed to viam-server. This behavior can be confusing, interfere with
|
|
140
|
+
# debugging, and is non-standard when compared to other languages. Here, stdout and stderr
|
|
141
|
+
# are reconfigured to immediately flush.
|
|
142
|
+
if isinstance(sys.stdout, io.TextIOWrapper):
|
|
143
|
+
sys.stdout.reconfigure(line_buffering=True)
|
|
144
|
+
if isinstance(sys.stderr, io.TextIOWrapper):
|
|
145
|
+
sys.stderr.reconfigure(line_buffering=True)
|
|
46
146
|
self._address = address
|
|
147
|
+
self._tcp_mode = tcp_mode
|
|
47
148
|
self.server = Server(resources=[], module_service=ModuleRPCService(self))
|
|
48
149
|
self._log_level = log_level
|
|
150
|
+
|
|
151
|
+
module_name = os.environ.get("VIAM_MODULE_NAME")
|
|
152
|
+
# this can happen if the user is running an old version of viam-server that doesn't set `VIAM_MODULE_NAME`
|
|
153
|
+
if module_name is None:
|
|
154
|
+
module_name = __name__
|
|
155
|
+
self.logger = logging.getLogger(module_name)
|
|
49
156
|
self._ready = True
|
|
50
157
|
self._lock = Lock()
|
|
51
158
|
|
|
52
159
|
async def _connect_to_parent(self):
|
|
160
|
+
if NO_MODULE_PARENT:
|
|
161
|
+
return
|
|
53
162
|
if self.parent is None:
|
|
54
163
|
if self._parent_address is None:
|
|
55
164
|
raise ValueError("Parent address not found")
|
|
@@ -60,40 +169,50 @@ class Module:
|
|
|
60
169
|
log_level=self._log_level,
|
|
61
170
|
),
|
|
62
171
|
)
|
|
172
|
+
self.logger.debug("Starting module logging")
|
|
173
|
+
logging.setParent(self.parent)
|
|
63
174
|
|
|
64
|
-
async def
|
|
175
|
+
async def _get_resource(self, name: ResourceName) -> ResourceBase:
|
|
65
176
|
await self._connect_to_parent()
|
|
66
177
|
assert self.parent is not None
|
|
67
178
|
await self.parent.refresh()
|
|
68
|
-
|
|
179
|
+
if name.type == RESOURCE_TYPE_COMPONENT:
|
|
180
|
+
return self.parent.get_component(name)
|
|
181
|
+
elif name.type == RESOURCE_TYPE_SERVICE:
|
|
182
|
+
return self.parent.get_service(name)
|
|
183
|
+
raise ValueError("Dependency does not describe a component nor a service")
|
|
69
184
|
|
|
70
|
-
async def _get_dependencies(self, dependencies: Sequence[str]) -> Mapping[ResourceName,
|
|
71
|
-
deps: Mapping[ResourceName,
|
|
185
|
+
async def _get_dependencies(self, dependencies: Sequence[str]) -> Mapping[ResourceName, ResourceBase]:
|
|
186
|
+
deps: Mapping[ResourceName, ResourceBase] = {}
|
|
72
187
|
for dep in dependencies:
|
|
73
188
|
rn = resource_name_from_string(dep)
|
|
74
|
-
|
|
75
|
-
deps[rn] = component
|
|
189
|
+
deps[rn] = await self._get_resource(rn)
|
|
76
190
|
return deps
|
|
77
191
|
|
|
78
192
|
async def start(self):
|
|
79
193
|
"""Start the module service and gRPC server"""
|
|
80
194
|
try:
|
|
81
|
-
|
|
195
|
+
if self._tcp_mode:
|
|
196
|
+
host, port = _host_port_from_url(self._address)
|
|
197
|
+
await self.server.serve(log_level=self._log_level, host=host, port=port)
|
|
198
|
+
else:
|
|
199
|
+
await self.server.serve(log_level=self._log_level, path=self._address)
|
|
82
200
|
finally:
|
|
83
201
|
await self.stop()
|
|
84
202
|
|
|
85
203
|
async def stop(self):
|
|
86
204
|
"""Stop the module service and gRPC server"""
|
|
87
|
-
|
|
205
|
+
self.logger.debug("Shutting down module")
|
|
88
206
|
try:
|
|
207
|
+
logging.shutdown()
|
|
89
208
|
if self.parent is not None:
|
|
90
209
|
await self.parent.close()
|
|
91
210
|
except Exception as e:
|
|
92
|
-
|
|
211
|
+
self.logger.error("Encountered error while shutting down module", exc_info=e)
|
|
93
212
|
|
|
94
213
|
def set_ready(self, ready: bool):
|
|
95
214
|
"""Set the module's ready state. The module automatically sets to READY on load. Setting to False can be useful
|
|
96
|
-
in instances where the module is not instantly ready (
|
|
215
|
+
in instances where the module is not instantly ready (for example waiting on hardware)
|
|
97
216
|
|
|
98
217
|
Args:
|
|
99
218
|
ready (bool): Whether the module is ready
|
|
@@ -101,21 +220,24 @@ class Module:
|
|
|
101
220
|
with self._lock:
|
|
102
221
|
self._ready = ready
|
|
103
222
|
|
|
104
|
-
async def add_resource(self, request: AddResourceRequest):
|
|
223
|
+
async def add_resource(self, request: AddResourceRequest, *, deadline: Optional[Deadline] = None):
|
|
105
224
|
dependencies = await self._get_dependencies(request.dependencies)
|
|
106
225
|
config: ComponentConfig = request.config
|
|
107
|
-
|
|
226
|
+
api = API.from_string(config.api)
|
|
108
227
|
model = Model.from_string(config.model, ignore_errors=True)
|
|
109
|
-
creator = Registry.lookup_resource_creator(
|
|
228
|
+
creator = Registry.lookup_resource_creator(api, model)
|
|
110
229
|
resource = creator(config, dependencies)
|
|
230
|
+
if deadline is not None and deadline.time_remaining() <= 0:
|
|
231
|
+
raise TimeoutError("Deadline expired")
|
|
232
|
+
update_log_level(resource.logger, config.log_configuration.level.upper())
|
|
111
233
|
self.server.register(resource)
|
|
112
234
|
|
|
113
235
|
async def reconfigure_resource(self, request: ReconfigureResourceRequest):
|
|
114
236
|
dependencies = await self._get_dependencies(request.dependencies)
|
|
115
237
|
config: ComponentConfig = request.config
|
|
116
|
-
|
|
238
|
+
api = API.from_string(config.api)
|
|
117
239
|
name = config.name
|
|
118
|
-
rn = ResourceName(namespace=
|
|
240
|
+
rn = ResourceName(namespace=api.namespace, type=api.resource_type, subtype=api.resource_subtype, name=name)
|
|
119
241
|
resource = self.server.get_resource(ResourceBase, rn)
|
|
120
242
|
if isinstance(resource, Reconfigurable):
|
|
121
243
|
resource.reconfigure(config, dependencies)
|
|
@@ -126,44 +248,48 @@ class Module:
|
|
|
126
248
|
else:
|
|
127
249
|
resource.stop()
|
|
128
250
|
add_request = AddResourceRequest(config=request.config, dependencies=request.dependencies)
|
|
129
|
-
self.server.remove_resource(rn)
|
|
251
|
+
await self.server.remove_resource(rn)
|
|
130
252
|
await self.add_resource(add_request)
|
|
131
253
|
|
|
132
254
|
async def remove_resource(self, request: RemoveResourceRequest):
|
|
133
255
|
rn = resource_name_from_string(request.name)
|
|
134
256
|
resource = self.server.get_resource(ResourceBase, rn)
|
|
135
257
|
if isinstance(resource, Stoppable):
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
258
|
+
try:
|
|
259
|
+
if iscoroutinefunction(resource.stop):
|
|
260
|
+
await resource.stop()
|
|
261
|
+
else:
|
|
262
|
+
resource.stop()
|
|
263
|
+
except Exception as e:
|
|
264
|
+
self.logger.warning(f"Could not remove resource named {resource.name}", exc_info=e)
|
|
265
|
+
await self.server.remove_resource(rn)
|
|
141
266
|
|
|
142
267
|
async def ready(self, request: ReadyRequest) -> ReadyResponse:
|
|
143
268
|
self._parent_address = request.parent_address
|
|
269
|
+
await self._connect_to_parent()
|
|
144
270
|
|
|
145
|
-
svcname_to_models: Mapping[Tuple[str,
|
|
146
|
-
for
|
|
147
|
-
|
|
148
|
-
|
|
271
|
+
svcname_to_models: Mapping[Tuple[str, API], List[Model]] = {}
|
|
272
|
+
for api_model_str in Registry.REGISTERED_RESOURCE_CREATORS().keys():
|
|
273
|
+
api_str, model_str = api_model_str.split("/")
|
|
274
|
+
api = API.from_string(api_str)
|
|
149
275
|
model = Model.from_string(model_str)
|
|
150
276
|
|
|
151
|
-
registration = Registry.
|
|
277
|
+
registration = Registry.lookup_api(api)
|
|
152
278
|
service = registration.rpc_service(self.server)
|
|
153
279
|
service_name = _service_name(service)
|
|
154
280
|
|
|
155
|
-
models = svcname_to_models.get((service_name,
|
|
281
|
+
models = svcname_to_models.get((service_name, api), [])
|
|
156
282
|
models.append(model)
|
|
157
|
-
svcname_to_models[(service_name,
|
|
283
|
+
svcname_to_models[(service_name, api)] = models
|
|
158
284
|
|
|
159
285
|
handlers: List[HandlerDefinition] = []
|
|
160
286
|
for key, value in svcname_to_models.items():
|
|
161
|
-
svc_name,
|
|
287
|
+
svc_name, api = key
|
|
162
288
|
rpc_subtype = ResourceRPCSubtype(
|
|
163
289
|
subtype=ResourceName(
|
|
164
|
-
namespace=
|
|
165
|
-
type=
|
|
166
|
-
subtype=
|
|
290
|
+
namespace=api.namespace,
|
|
291
|
+
type=api.resource_type,
|
|
292
|
+
subtype=api.resource_subtype,
|
|
167
293
|
name="",
|
|
168
294
|
),
|
|
169
295
|
proto_service=svc_name,
|
|
@@ -173,22 +299,43 @@ class Module:
|
|
|
173
299
|
|
|
174
300
|
return ReadyResponse(ready=self._ready, handlermap=HandlerMap(handlers=handlers))
|
|
175
301
|
|
|
176
|
-
def add_model_from_registry(self,
|
|
302
|
+
def add_model_from_registry(self, api: API, model: Model):
|
|
177
303
|
"""Add a pre-registered model to this Module"""
|
|
178
304
|
|
|
179
305
|
# All we need to do is double check that the model has already been registered
|
|
180
306
|
try:
|
|
181
|
-
Registry.lookup_resource_creator(
|
|
307
|
+
Registry.lookup_resource_creator(api, model)
|
|
182
308
|
except ResourceNotFoundError:
|
|
183
|
-
raise ValueError(f"Cannot add model because it has not been registered.
|
|
309
|
+
raise ValueError(f"Cannot add model because it has not been registered. API: {api}. Model: {model}")
|
|
184
310
|
|
|
185
311
|
async def validate_config(self, request: ValidateConfigRequest) -> ValidateConfigResponse:
|
|
186
312
|
config: ComponentConfig = request.config
|
|
187
|
-
|
|
313
|
+
api = API.from_string(config.api)
|
|
188
314
|
model = Model.from_string(config.model)
|
|
189
|
-
validator = Registry.lookup_validator(
|
|
315
|
+
validator = Registry.lookup_validator(api, model)
|
|
190
316
|
try:
|
|
191
|
-
|
|
192
|
-
|
|
317
|
+
# backwards compatibility. Support both ([], []) or [] with deprecation warning.
|
|
318
|
+
# If user's validate returns [str], it will be treated as required dependencies only.
|
|
319
|
+
# Incorect formats, e.g. int, will raise ValidationError.
|
|
320
|
+
_validator_return_test = validator(config)
|
|
321
|
+
if not (isinstance(_validator_return_test, tuple) and len(_validator_return_test) == 2):
|
|
322
|
+
msg = f"Your validate function {validator.__name__} did not return \
|
|
323
|
+
type tuple[Sequence[str], Sequence[str]]. Got {_validator_return_test}."
|
|
324
|
+
self.logger.warning(msg)
|
|
325
|
+
if (isinstance(_validator_return_test, Iterable) and not isinstance(_validator_return_test, str)) and all(
|
|
326
|
+
isinstance(e, str)
|
|
327
|
+
for e in _validator_return_test # type: ignore
|
|
328
|
+
):
|
|
329
|
+
self.logger.warning(
|
|
330
|
+
f"Detected deprecated validate function signature. \
|
|
331
|
+
Treating all dependencies {_validator_return_test} as required dependencies. \
|
|
332
|
+
Please update to new signature Tuple[Sequence[str], Sequence[str]] soon."
|
|
333
|
+
)
|
|
334
|
+
return ValidateConfigResponse(dependencies=_validator_return_test)
|
|
335
|
+
else:
|
|
336
|
+
raise ValidationError(msg)
|
|
337
|
+
|
|
338
|
+
dependencies, optional_dependencies = _validator_return_test
|
|
339
|
+
return ValidateConfigResponse(dependencies=dependencies, optional_dependencies=optional_dependencies)
|
|
193
340
|
except Exception as e:
|
|
194
341
|
raise ValidationError(f"{type(Exception)}: {e}").grpc_error
|