viam-sdk 0.41.1__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.

Files changed (225) hide show
  1. viam/app/app_client.py +225 -51
  2. viam/app/billing_client.py +47 -5
  3. viam/app/data_client.py +771 -234
  4. viam/app/ml_training_client.py +3 -5
  5. viam/app/provisioning_client.py +3 -5
  6. viam/app/viam_client.py +58 -11
  7. viam/components/arm/arm.py +1 -1
  8. viam/components/arm/service.py +1 -1
  9. viam/components/audio_in/__init__.py +24 -0
  10. viam/components/audio_in/audio_in.py +74 -0
  11. viam/components/audio_in/client.py +76 -0
  12. viam/components/audio_in/service.py +83 -0
  13. viam/components/audio_out/__init__.py +21 -0
  14. viam/components/audio_out/audio_out.py +72 -0
  15. viam/components/audio_out/client.py +67 -0
  16. viam/components/audio_out/service.py +63 -0
  17. viam/components/base/base.py +1 -1
  18. viam/components/board/board.py +8 -2
  19. viam/components/board/client.py +2 -1
  20. viam/components/board/service.py +1 -0
  21. viam/components/button/__init__.py +10 -0
  22. viam/components/button/button.py +41 -0
  23. viam/components/button/client.py +52 -0
  24. viam/components/button/service.py +46 -0
  25. viam/components/camera/camera.py +15 -30
  26. viam/components/camera/client.py +10 -21
  27. viam/components/camera/service.py +15 -28
  28. viam/components/component_base.py +2 -2
  29. viam/components/gantry/client.py +17 -2
  30. viam/components/gantry/gantry.py +32 -1
  31. viam/components/gantry/service.py +21 -5
  32. viam/components/gripper/__init__.py +2 -0
  33. viam/components/gripper/client.py +25 -2
  34. viam/components/gripper/gripper.py +76 -1
  35. viam/components/gripper/service.py +32 -3
  36. viam/components/input/input.py +1 -1
  37. viam/components/motor/motor.py +1 -1
  38. viam/components/power_sensor/power_sensor.py +1 -1
  39. viam/components/switch/__init__.py +10 -0
  40. viam/components/switch/client.py +83 -0
  41. viam/components/switch/service.py +72 -0
  42. viam/components/switch/switch.py +98 -0
  43. viam/gen/app/agent/v1/agent_pb2.py +1 -1
  44. viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +1 -1
  45. viam/gen/app/data/v1/data_grpc.py +74 -2
  46. viam/gen/app/data/v1/data_pb2.py +198 -104
  47. viam/gen/app/data/v1/data_pb2.pyi +563 -31
  48. viam/gen/app/datapipelines/__init__.py +0 -0
  49. viam/gen/app/datapipelines/v1/__init__.py +0 -0
  50. viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
  51. viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +57 -0
  52. viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +387 -0
  53. viam/gen/app/dataset/v1/dataset_grpc.py +10 -2
  54. viam/gen/app/dataset/v1/dataset_pb2.py +8 -4
  55. viam/gen/app/dataset/v1/dataset_pb2.pyi +36 -1
  56. viam/gen/app/datasync/v1/data_sync_pb2.py +39 -35
  57. viam/gen/app/datasync/v1/data_sync_pb2.pyi +21 -8
  58. viam/gen/app/mlinference/v1/ml_inference_pb2.py +7 -7
  59. viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +4 -2
  60. viam/gen/app/mltraining/v1/ml_training_grpc.py +10 -2
  61. viam/gen/app/mltraining/v1/ml_training_pb2.py +63 -43
  62. viam/gen/app/mltraining/v1/ml_training_pb2.pyi +112 -7
  63. viam/gen/app/packages/v1/packages_pb2.py +1 -1
  64. viam/gen/app/v1/app_grpc.py +74 -3
  65. viam/gen/app/v1/app_pb2.py +600 -545
  66. viam/gen/app/v1/app_pb2.pyi +1108 -258
  67. viam/gen/app/v1/billing_grpc.py +26 -2
  68. viam/gen/app/v1/billing_pb2.py +52 -36
  69. viam/gen/app/v1/billing_pb2.pyi +158 -4
  70. viam/gen/app/v1/end_user_pb2.py +1 -1
  71. viam/gen/app/v1/robot_pb2.py +95 -89
  72. viam/gen/app/v1/robot_pb2.pyi +121 -9
  73. viam/gen/common/v1/common_pb2.py +76 -58
  74. viam/gen/common/v1/common_pb2.pyi +186 -17
  75. viam/gen/component/arm/v1/arm_grpc.py +10 -2
  76. viam/gen/component/arm/v1/arm_pb2.py +5 -3
  77. viam/gen/component/audioin/__init__.py +0 -0
  78. viam/gen/component/audioin/v1/__init__.py +0 -0
  79. viam/gen/component/audioin/v1/audioin_grpc.py +54 -0
  80. viam/gen/component/audioin/v1/audioin_pb2.py +34 -0
  81. viam/gen/component/audioin/v1/audioin_pb2.pyi +94 -0
  82. viam/gen/component/audioinput/v1/audioinput_pb2.py +1 -1
  83. viam/gen/component/audioout/__init__.py +0 -0
  84. viam/gen/component/audioout/v1/__init__.py +0 -0
  85. viam/gen/component/audioout/v1/audioout_grpc.py +54 -0
  86. viam/gen/component/audioout/v1/audioout_pb2.py +32 -0
  87. viam/gen/component/audioout/v1/audioout_pb2.pyi +47 -0
  88. viam/gen/component/base/v1/base_pb2.py +1 -1
  89. viam/gen/component/board/v1/board_pb2.py +1 -1
  90. viam/gen/component/button/v1/button_pb2.py +1 -1
  91. viam/gen/component/camera/v1/camera_grpc.py +1 -0
  92. viam/gen/component/camera/v1/camera_pb2.py +37 -36
  93. viam/gen/component/camera/v1/camera_pb2.pyi +31 -4
  94. viam/gen/component/encoder/v1/encoder_pb2.py +1 -1
  95. viam/gen/component/gantry/v1/gantry_grpc.py +9 -1
  96. viam/gen/component/gantry/v1/gantry_pb2.py +5 -3
  97. viam/gen/component/generic/v1/generic_pb2.py +1 -1
  98. viam/gen/component/gripper/v1/gripper_grpc.py +18 -2
  99. viam/gen/component/gripper/v1/gripper_pb2.py +12 -4
  100. viam/gen/component/gripper/v1/gripper_pb2.pyi +43 -1
  101. viam/gen/component/inputcontroller/v1/input_controller_pb2.py +1 -1
  102. viam/gen/component/motor/v1/motor_pb2.py +1 -1
  103. viam/gen/component/movementsensor/v1/movementsensor_pb2.py +1 -1
  104. viam/gen/component/posetracker/v1/pose_tracker_pb2.py +1 -1
  105. viam/gen/component/powersensor/v1/powersensor_pb2.py +1 -1
  106. viam/gen/component/sensor/v1/sensor_pb2.py +1 -1
  107. viam/gen/component/servo/v1/servo_pb2.py +1 -1
  108. viam/gen/component/switch/v1/switch_pb2.py +5 -5
  109. viam/gen/component/switch/v1/switch_pb2.pyi +9 -2
  110. viam/gen/component/testecho/v1/testecho_pb2.py +1 -1
  111. viam/gen/module/v1/module_pb2.py +5 -5
  112. viam/gen/module/v1/module_pb2.pyi +7 -2
  113. viam/gen/opentelemetry/__init__.py +0 -0
  114. viam/gen/opentelemetry/proto/__init__.py +0 -0
  115. viam/gen/opentelemetry/proto/common/__init__.py +0 -0
  116. viam/gen/opentelemetry/proto/common/v1/__init__.py +0 -0
  117. viam/gen/opentelemetry/proto/common/v1/common_grpc.py +0 -0
  118. viam/gen/opentelemetry/proto/common/v1/common_pb2.py +27 -0
  119. viam/gen/opentelemetry/proto/common/v1/common_pb2.pyi +208 -0
  120. viam/gen/opentelemetry/proto/resource/__init__.py +0 -0
  121. viam/gen/opentelemetry/proto/resource/v1/__init__.py +0 -0
  122. viam/gen/opentelemetry/proto/resource/v1/resource_grpc.py +0 -0
  123. viam/gen/opentelemetry/proto/resource/v1/resource_pb2.py +18 -0
  124. viam/gen/opentelemetry/proto/resource/v1/resource_pb2.pyi +59 -0
  125. viam/gen/opentelemetry/proto/trace/__init__.py +0 -0
  126. viam/gen/opentelemetry/proto/trace/v1/__init__.py +0 -0
  127. viam/gen/opentelemetry/proto/trace/v1/trace_grpc.py +0 -0
  128. viam/gen/opentelemetry/proto/trace/v1/trace_pb2.py +37 -0
  129. viam/gen/opentelemetry/proto/trace/v1/trace_pb2.pyi +402 -0
  130. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +1 -1
  131. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +1 -1
  132. viam/gen/proto/rpc/v1/auth_pb2.py +1 -1
  133. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +1 -1
  134. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +1 -1
  135. viam/gen/provisioning/v1/provisioning_grpc.py +10 -2
  136. viam/gen/provisioning/v1/provisioning_pb2.py +32 -26
  137. viam/gen/provisioning/v1/provisioning_pb2.pyi +46 -5
  138. viam/gen/robot/v1/robot_grpc.py +51 -34
  139. viam/gen/robot/v1/robot_pb2.py +147 -142
  140. viam/gen/robot/v1/robot_pb2.pyi +153 -86
  141. viam/gen/service/datamanager/v1/data_manager_grpc.py +11 -2
  142. viam/gen/service/datamanager/v1/data_manager_pb2.py +15 -8
  143. viam/gen/service/datamanager/v1/data_manager_pb2.pyi +47 -1
  144. viam/gen/service/discovery/v1/discovery_pb2.py +1 -1
  145. viam/gen/service/generic/v1/generic_pb2.py +1 -1
  146. viam/gen/service/mlmodel/v1/mlmodel_pb2.py +1 -1
  147. viam/gen/service/motion/v1/motion_pb2.py +92 -62
  148. viam/gen/service/motion/v1/motion_pb2.pyi +130 -68
  149. viam/gen/service/navigation/v1/navigation_pb2.py +1 -1
  150. viam/gen/service/sensors/v1/sensors_pb2.py +1 -1
  151. viam/gen/service/shell/v1/shell_pb2.py +1 -1
  152. viam/gen/service/slam/v1/slam_pb2.py +1 -1
  153. viam/gen/service/slam/v1/slam_pb2.pyi +1 -1
  154. viam/gen/service/video/__init__.py +0 -0
  155. viam/gen/service/video/v1/__init__.py +0 -0
  156. viam/gen/service/video/v1/video_grpc.py +39 -0
  157. viam/gen/service/video/v1/video_pb2.py +29 -0
  158. viam/gen/service/video/v1/video_pb2.pyi +72 -0
  159. viam/gen/service/vision/v1/vision_pb2.py +27 -27
  160. viam/gen/service/vision/v1/vision_pb2.pyi +28 -3
  161. viam/gen/service/worldstatestore/__init__.py +0 -0
  162. viam/gen/service/worldstatestore/v1/__init__.py +0 -0
  163. viam/gen/service/worldstatestore/v1/world_state_store_grpc.py +55 -0
  164. viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +39 -0
  165. viam/gen/service/worldstatestore/v1/world_state_store_pb2.pyi +171 -0
  166. viam/gen/stream/v1/stream_pb2.py +1 -1
  167. viam/gen/tagger/v1/tagger_pb2.py +1 -1
  168. viam/logging.py +9 -8
  169. viam/media/audio.py +22 -10
  170. viam/media/utils/pil/__init__.py +5 -1
  171. viam/media/video.py +54 -40
  172. viam/module/module.py +85 -16
  173. viam/module/resource_data_consumer.py +41 -0
  174. viam/module/service.py +9 -1
  175. viam/proto/app/__init__.py +68 -0
  176. viam/proto/app/billing.py +16 -0
  177. viam/proto/app/data/__init__.py +48 -0
  178. viam/proto/app/datapipelines/__init__.py +56 -0
  179. viam/proto/app/dataset/__init__.py +4 -0
  180. viam/proto/app/mltraining/__init__.py +6 -0
  181. viam/proto/app/robot.py +6 -0
  182. viam/proto/common/__init__.py +14 -0
  183. viam/proto/component/audioin/__init__.py +16 -0
  184. viam/proto/component/audioout/__init__.py +15 -0
  185. viam/proto/component/camera/__init__.py +0 -2
  186. viam/proto/component/gripper/__init__.py +4 -0
  187. viam/proto/opentelemetry/__init__.py +0 -0
  188. viam/proto/opentelemetry/proto/__init__.py +0 -0
  189. viam/proto/opentelemetry/proto/common/__init__.py +15 -0
  190. viam/proto/opentelemetry/proto/resource/__init__.py +10 -0
  191. viam/proto/opentelemetry/proto/trace/__init__.py +15 -0
  192. viam/proto/provisioning/__init__.py +6 -0
  193. viam/proto/robot/__init__.py +16 -8
  194. viam/proto/service/datamanager/__init__.py +8 -1
  195. viam/proto/service/motion/__init__.py +2 -0
  196. viam/proto/service/video/__init__.py +15 -0
  197. viam/proto/service/worldstatestore/__init__.py +32 -0
  198. viam/resource/easy_resource.py +5 -9
  199. viam/resource/manager.py +4 -3
  200. viam/resource/registry.py +2 -2
  201. viam/resource/types.py +2 -2
  202. viam/robot/client.py +38 -59
  203. viam/rpc/dial.py +48 -5
  204. viam/rpc/libviam_rust_utils.so +0 -0
  205. viam/rpc/server.py +24 -10
  206. viam/services/motion/client.py +8 -9
  207. viam/services/motion/motion.py +48 -46
  208. viam/services/navigation/navigation.py +2 -2
  209. viam/services/vision/client.py +1 -1
  210. viam/services/vision/service.py +5 -8
  211. viam/services/vision/vision.py +5 -3
  212. viam/services/worldstatestore/__init__.py +18 -0
  213. viam/services/worldstatestore/client.py +94 -0
  214. viam/services/worldstatestore/service.py +55 -0
  215. viam/services/worldstatestore/worldstatestore.py +90 -0
  216. viam/sessions_client.py +115 -46
  217. viam/version_metadata.py +2 -2
  218. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/METADATA +10 -6
  219. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/RECORD +221 -152
  220. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/WHEEL +1 -1
  221. viam/components/audio_input/__init__.py +0 -18
  222. viam/components/audio_input/audio_input.py +0 -81
  223. viam/components/audio_input/client.py +0 -70
  224. viam/components/audio_input/service.py +0 -114
  225. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/licenses/LICENSE +0 -0
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
- def __init__(self, channel: Channel, direct_dial_address: str, dial_options: Optional[DialOptions], *, disabled: bool = False):
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
- self._dial_options.disable_webrtc = True
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 in EXEMPT_METADATA_METHODS:
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._lock:
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
- request = StartSessionRequest(resume=self._current_id)
112
- try:
113
- response: StartSessionResponse = await self.client.StartSession(request)
114
- except GRPCError as error:
115
- if error.status == Status.UNIMPLEMENTED:
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
- else:
121
- raise
135
+ else:
136
+ raise
122
137
 
123
- if response is None:
124
- raise GRPCError(status=Status.INTERNAL, message="Expected response to start session")
138
+ if response is None:
139
+ raise GRPCError(status=Status.INTERNAL, message="Expected response to start session")
125
140
 
126
- if response.heartbeat_window is None:
127
- raise GRPCError(status=Status.INTERNAL, message="Expected heartbeat window in response to start session")
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
- # tick once to ensure heartbeats are supported
135
- await self._heartbeat_tick(self.client)
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
- with self._lock:
157
- if not self._current_id:
158
- LOGGER.debug("Failed to send heartbeat, session client reset")
159
- return
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.reset()
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
- channel = await dial(address=self._address, options=self._dial_options)
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._lock:
197
+ async with self._acquire_lock_async():
175
198
  if self._supported != _SupportedState.TRUE:
176
199
  return
177
- await self._heartbeat_tick(client)
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/version_metadata.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.41.1"
1
+ __version__ = "0.66.0"
2
2
 
3
- API_VERSION = "v0.1.395"
3
+ API_VERSION = "v0.1.507"
4
4
  SDK_VERSION = __version__
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: viam-sdk
3
- Version: 0.41.1
3
+ Version: 0.66.0
4
4
  Summary: Viam Robotics Python SDK
5
5
  Project-URL: Homepage, https://www.viam.com
6
6
  Project-URL: Documentation, https://python.viam.dev
@@ -11,7 +11,7 @@ License-File: LICENSE
11
11
  Requires-Python: >=3.8.1
12
12
  Requires-Dist: googleapis-common-protos>=1.65.0
13
13
  Requires-Dist: grpclib>=0.4.7
14
- Requires-Dist: protobuf==5.29.2
14
+ Requires-Dist: protobuf==5.29.5
15
15
  Requires-Dist: pymongo>=4.10.1
16
16
  Requires-Dist: typing-extensions>=4.12.2
17
17
  Provides-Extra: mlmodel
@@ -38,6 +38,12 @@ Currently, we have pre-built binaries for macOS (both Intel `x86_64` and Apple S
38
38
 
39
39
  `pip install viam-sdk`
40
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
+
41
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:
42
48
 
43
49
  `pip install 'viam-sdk[mlmodel]'`
@@ -45,8 +51,6 @@ If you intend to use the [`MLModel` service](https://python.viam.dev/autoapi/via
45
51
  You can also run this command on an existing Python SDK install to add support for the ML model service.
46
52
  See the [ML (machine learning) model service](https://docs.viam.com/data-ai/ai/deploy/) documentation for more information.
47
53
 
48
- 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.
49
-
50
54
  ### Upgrading
51
55
 
52
56
  To upgrade, simply run the `pip install` command with the `-U` option:
@@ -88,7 +92,7 @@ To create a client application, to navigate to [app.viam.com](https://app.viam.c
88
92
  2. Create a robot (for example `arduino`)
89
93
  3. Follow the steps on the setup tab:
90
94
 
91
- 1. Setup Viam App Config on Single Board Computer (SBC)
95
+ 1. Setup machine cloud credentials on Single Board Computer (SBC)
92
96
  2. Download and Install Viam Server
93
97
  3. Wait until the robot shows as connected. If this doesn't happen try restarting the viam-server:
94
98
 
@@ -96,7 +100,7 @@ To create a client application, to navigate to [app.viam.com](https://app.viam.c
96
100
  sudo systemctl restart viam-server
97
101
  ```
98
102
 
99
- Next, select the `CODE SAMPLE` tab in the Viam Web UI, and copy the boilerplate code from the section labeled `Python SDK`.
103
+ Next, select the `CONNECT` tab in the Viam Web UI, and copy the boilerplate code from the section labeled `Python SDK`.
100
104
 
101
105
  To ensure the installation succeeded and the systems are functional, save and run this simple program. If the program runs successfully, the python-sdk is properly installed, the `viam-server` instance on your robot is alive, and the computer running the program is able to connect to that instance.
102
106