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.

Files changed (452) hide show
  1. viam/__init__.py +29 -2
  2. viam/app/_logs.py +34 -0
  3. viam/app/app_client.py +2696 -0
  4. viam/app/billing_client.py +185 -0
  5. viam/app/data_client.py +2231 -0
  6. viam/app/ml_training_client.py +249 -0
  7. viam/app/provisioning_client.py +93 -0
  8. viam/app/viam_client.py +275 -0
  9. viam/components/arm/__init__.py +3 -26
  10. viam/components/arm/arm.py +123 -8
  11. viam/components/arm/client.py +37 -24
  12. viam/components/arm/service.py +35 -32
  13. viam/components/audio_in/__init__.py +24 -0
  14. viam/components/audio_in/audio_in.py +74 -0
  15. viam/components/audio_in/client.py +76 -0
  16. viam/components/audio_in/service.py +83 -0
  17. viam/components/audio_out/__init__.py +21 -0
  18. viam/components/audio_out/audio_out.py +72 -0
  19. viam/components/audio_out/client.py +67 -0
  20. viam/components/audio_out/service.py +63 -0
  21. viam/components/base/__init__.py +6 -11
  22. viam/components/base/base.py +134 -8
  23. viam/components/base/client.py +51 -23
  24. viam/components/base/service.py +33 -30
  25. viam/components/board/__init__.py +3 -12
  26. viam/components/board/board.py +247 -91
  27. viam/components/board/client.py +149 -83
  28. viam/components/board/service.py +63 -33
  29. viam/components/button/__init__.py +10 -0
  30. viam/components/button/button.py +41 -0
  31. viam/components/button/client.py +52 -0
  32. viam/components/button/service.py +46 -0
  33. viam/components/camera/__init__.py +3 -3
  34. viam/components/camera/camera.py +62 -27
  35. viam/components/camera/client.py +59 -27
  36. viam/components/camera/service.py +42 -65
  37. viam/components/component_base.py +28 -5
  38. viam/components/encoder/__init__.py +1 -1
  39. viam/components/encoder/client.py +25 -14
  40. viam/components/encoder/encoder.py +48 -10
  41. viam/components/encoder/service.py +14 -18
  42. viam/components/gantry/__init__.py +1 -13
  43. viam/components/gantry/client.py +80 -25
  44. viam/components/gantry/gantry.py +123 -9
  45. viam/components/gantry/service.py +51 -29
  46. viam/components/generic/__init__.py +1 -1
  47. viam/components/generic/client.py +21 -8
  48. viam/components/generic/generic.py +10 -2
  49. viam/components/generic/service.py +12 -7
  50. viam/components/gripper/__init__.py +3 -13
  51. viam/components/gripper/client.py +69 -21
  52. viam/components/gripper/gripper.py +123 -3
  53. viam/components/gripper/service.py +44 -22
  54. viam/components/input/__init__.py +1 -14
  55. viam/components/input/client.py +55 -23
  56. viam/components/input/input.py +106 -3
  57. viam/components/input/service.py +16 -21
  58. viam/components/motor/__init__.py +1 -21
  59. viam/components/motor/client.py +56 -33
  60. viam/components/motor/motor.py +127 -4
  61. viam/components/motor/service.py +33 -44
  62. viam/components/movement_sensor/__init__.py +1 -1
  63. viam/components/movement_sensor/client.py +102 -45
  64. viam/components/movement_sensor/movement_sensor.py +130 -61
  65. viam/components/movement_sensor/service.py +38 -41
  66. viam/components/pose_tracker/__init__.py +1 -1
  67. viam/components/pose_tracker/client.py +18 -7
  68. viam/components/pose_tracker/pose_tracker.py +4 -2
  69. viam/components/pose_tracker/service.py +12 -10
  70. viam/components/power_sensor/__init__.py +17 -0
  71. viam/components/power_sensor/client.py +86 -0
  72. viam/components/power_sensor/power_sensor.py +104 -0
  73. viam/components/power_sensor/service.py +72 -0
  74. viam/components/sensor/__init__.py +2 -1
  75. viam/components/sensor/client.py +26 -10
  76. viam/components/sensor/sensor.py +22 -4
  77. viam/components/sensor/service.py +20 -11
  78. viam/components/servo/__init__.py +1 -13
  79. viam/components/servo/client.py +47 -21
  80. viam/components/servo/service.py +15 -22
  81. viam/components/servo/servo.py +61 -2
  82. viam/components/switch/__init__.py +10 -0
  83. viam/components/switch/client.py +83 -0
  84. viam/components/switch/service.py +72 -0
  85. viam/components/switch/switch.py +98 -0
  86. viam/errors.py +10 -0
  87. viam/gen/app/agent/v1/agent_grpc.py +29 -0
  88. viam/gen/app/agent/v1/agent_pb2.py +47 -0
  89. viam/gen/app/agent/v1/agent_pb2.pyi +280 -0
  90. viam/gen/app/cloudslam/v1/__init__.py +0 -0
  91. viam/gen/app/cloudslam/v1/cloud_slam_grpc.py +70 -0
  92. viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +54 -0
  93. viam/gen/app/cloudslam/v1/cloud_slam_pb2.pyi +384 -0
  94. viam/gen/app/data/v1/data_grpc.py +197 -8
  95. viam/gen/app/data/v1/data_pb2.py +238 -99
  96. viam/gen/app/data/v1/data_pb2.pyi +1222 -259
  97. viam/gen/app/datapipelines/__init__.py +0 -0
  98. viam/gen/app/datapipelines/v1/__init__.py +0 -0
  99. viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
  100. viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +57 -0
  101. viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +387 -0
  102. viam/gen/app/dataset/__init__.py +0 -0
  103. viam/gen/app/dataset/v1/__init__.py +0 -0
  104. viam/gen/app/dataset/v1/dataset_grpc.py +68 -0
  105. viam/gen/app/dataset/v1/dataset_pb2.py +44 -0
  106. viam/gen/app/dataset/v1/dataset_pb2.pyi +214 -0
  107. viam/gen/app/datasync/v1/data_sync_grpc.py +21 -4
  108. viam/gen/app/datasync/v1/data_sync_pb2.py +62 -128
  109. viam/gen/app/datasync/v1/data_sync_pb2.pyi +156 -199
  110. viam/gen/app/mlinference/__init__.py +0 -0
  111. viam/gen/app/mlinference/v1/__init__.py +0 -0
  112. viam/gen/app/mlinference/v1/ml_inference_grpc.py +28 -0
  113. viam/gen/app/mlinference/v1/ml_inference_pb2.py +23 -0
  114. viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +63 -0
  115. viam/gen/app/mltraining/v1/ml_training_grpc.py +51 -3
  116. viam/gen/app/mltraining/v1/ml_training_pb2.py +135 -58
  117. viam/gen/app/mltraining/v1/ml_training_pb2.pyi +328 -39
  118. viam/gen/app/packages/v1/packages_grpc.py +15 -1
  119. viam/gen/app/packages/v1/packages_pb2.py +44 -64
  120. viam/gen/app/packages/v1/packages_pb2.pyi +75 -85
  121. viam/gen/app/v1/app_grpc.py +644 -3
  122. viam/gen/app/v1/app_pb2.py +695 -295
  123. viam/gen/app/v1/app_pb2.pyi +4488 -635
  124. viam/gen/app/v1/billing_grpc.py +53 -11
  125. viam/gen/app/v1/billing_pb2.py +94 -39
  126. viam/gen/app/v1/billing_pb2.pyi +391 -191
  127. viam/gen/app/v1/end_user_grpc.py +59 -0
  128. viam/gen/app/v1/end_user_pb2.py +55 -0
  129. viam/gen/app/v1/end_user_pb2.pyi +181 -0
  130. viam/gen/app/v1/robot_grpc.py +16 -1
  131. viam/gen/app/v1/robot_pb2.py +122 -94
  132. viam/gen/app/v1/robot_pb2.pyi +463 -123
  133. viam/gen/common/v1/common_pb2.py +87 -58
  134. viam/gen/common/v1/common_pb2.pyi +456 -149
  135. viam/gen/component/arm/v1/arm_grpc.py +58 -2
  136. viam/gen/component/arm/v1/arm_pb2.py +68 -51
  137. viam/gen/component/arm/v1/arm_pb2.pyi +108 -42
  138. viam/gen/component/audioin/__init__.py +0 -0
  139. viam/gen/component/audioin/v1/__init__.py +0 -0
  140. viam/gen/component/audioin/v1/audioin_grpc.py +54 -0
  141. viam/gen/component/audioin/v1/audioin_pb2.py +34 -0
  142. viam/gen/component/audioin/v1/audioin_pb2.pyi +94 -0
  143. viam/gen/component/audioinput/v1/audioinput_grpc.py +25 -2
  144. viam/gen/component/audioinput/v1/audioinput_pb2.py +36 -31
  145. viam/gen/component/audioinput/v1/audioinput_pb2.pyi +22 -22
  146. viam/gen/component/audioout/__init__.py +0 -0
  147. viam/gen/component/audioout/v1/__init__.py +0 -0
  148. viam/gen/component/audioout/v1/audioout_grpc.py +54 -0
  149. viam/gen/component/audioout/v1/audioout_pb2.py +32 -0
  150. viam/gen/component/audioout/v1/audioout_pb2.pyi +47 -0
  151. viam/gen/component/base/v1/base_grpc.py +42 -2
  152. viam/gen/component/base/v1/base_pb2.py +58 -47
  153. viam/gen/component/base/v1/base_pb2.pyi +65 -30
  154. viam/gen/component/board/v1/board_grpc.py +59 -7
  155. viam/gen/component/board/v1/board_pb2.py +94 -73
  156. viam/gen/component/board/v1/board_pb2.pyi +165 -68
  157. viam/gen/component/button/__init__.py +0 -0
  158. viam/gen/component/button/v1/__init__.py +0 -0
  159. viam/gen/component/button/v1/button_grpc.py +38 -0
  160. viam/gen/component/button/v1/button_pb2.py +28 -0
  161. viam/gen/component/button/v1/button_pb2.pyi +39 -0
  162. viam/gen/component/camera/v1/camera_grpc.py +38 -2
  163. viam/gen/component/camera/v1/camera_pb2.py +60 -43
  164. viam/gen/component/camera/v1/camera_pb2.pyi +191 -37
  165. viam/gen/component/encoder/v1/encoder_grpc.py +25 -2
  166. viam/gen/component/encoder/v1/encoder_pb2.py +36 -31
  167. viam/gen/component/encoder/v1/encoder_pb2.pyi +15 -15
  168. viam/gen/component/gantry/v1/gantry_grpc.py +47 -2
  169. viam/gen/component/gantry/v1/gantry_pb2.py +56 -43
  170. viam/gen/component/gantry/v1/gantry_pb2.pyi +67 -31
  171. viam/gen/component/generic/v1/generic_grpc.py +16 -2
  172. viam/gen/component/generic/v1/generic_pb2.py +16 -11
  173. viam/gen/component/gripper/v1/gripper_grpc.py +44 -2
  174. viam/gen/component/gripper/v1/gripper_pb2.py +48 -35
  175. viam/gen/component/gripper/v1/gripper_pb2.pyi +62 -24
  176. viam/gen/component/inputcontroller/v1/input_controller_grpc.py +28 -2
  177. viam/gen/component/inputcontroller/v1/input_controller_pb2.py +46 -41
  178. viam/gen/component/inputcontroller/v1/input_controller_pb2.pyi +32 -36
  179. viam/gen/component/motor/v1/motor_grpc.py +51 -2
  180. viam/gen/component/motor/v1/motor_pb2.py +78 -67
  181. viam/gen/component/motor/v1/motor_pb2.pyi +75 -46
  182. viam/gen/component/movementsensor/v1/movementsensor_grpc.py +48 -2
  183. viam/gen/component/movementsensor/v1/movementsensor_pb2.py +70 -63
  184. viam/gen/component/movementsensor/v1/movementsensor_pb2.pyi +84 -57
  185. viam/gen/component/posetracker/v1/pose_tracker_grpc.py +19 -2
  186. viam/gen/component/posetracker/v1/pose_tracker_pb2.py +26 -21
  187. viam/gen/component/posetracker/v1/pose_tracker_pb2.pyi +9 -13
  188. viam/gen/component/powersensor/__init__.py +0 -0
  189. viam/gen/component/powersensor/v1/__init__.py +0 -0
  190. viam/gen/component/powersensor/v1/powersensor_grpc.py +62 -0
  191. viam/gen/component/powersensor/v1/powersensor_pb2.py +42 -0
  192. viam/gen/component/powersensor/v1/powersensor_pb2.pyi +124 -0
  193. viam/gen/component/sensor/v1/sensor_grpc.py +21 -5
  194. viam/gen/component/sensor/v1/sensor_pb2.py +18 -22
  195. viam/gen/component/sensor/v1/sensor_pb2.pyi +1 -69
  196. viam/gen/component/servo/v1/servo_grpc.py +28 -2
  197. viam/gen/component/servo/v1/servo_pb2.py +42 -37
  198. viam/gen/component/servo/v1/servo_pb2.pyi +22 -26
  199. viam/gen/component/switch/__init__.py +0 -0
  200. viam/gen/component/switch/v1/__init__.py +0 -0
  201. viam/gen/component/switch/v1/switch_grpc.py +54 -0
  202. viam/gen/component/switch/v1/switch_pb2.py +40 -0
  203. viam/gen/component/switch/v1/switch_pb2.pyi +116 -0
  204. viam/gen/component/testecho/v1/testecho_grpc.py +15 -0
  205. viam/gen/component/testecho/v1/testecho_pb2.py +29 -26
  206. viam/gen/component/testecho/v1/testecho_pb2.pyi +16 -20
  207. viam/gen/module/v1/module_grpc.py +18 -0
  208. viam/gen/module/v1/module_pb2.py +36 -33
  209. viam/gen/module/v1/module_pb2.pyi +39 -34
  210. viam/gen/opentelemetry/__init__.py +0 -0
  211. viam/gen/opentelemetry/proto/__init__.py +0 -0
  212. viam/gen/opentelemetry/proto/common/__init__.py +0 -0
  213. viam/gen/opentelemetry/proto/common/v1/__init__.py +0 -0
  214. viam/gen/opentelemetry/proto/common/v1/common_grpc.py +0 -0
  215. viam/gen/opentelemetry/proto/common/v1/common_pb2.py +27 -0
  216. viam/gen/opentelemetry/proto/common/v1/common_pb2.pyi +208 -0
  217. viam/gen/opentelemetry/proto/resource/__init__.py +0 -0
  218. viam/gen/opentelemetry/proto/resource/v1/__init__.py +0 -0
  219. viam/gen/opentelemetry/proto/resource/v1/resource_grpc.py +0 -0
  220. viam/gen/opentelemetry/proto/resource/v1/resource_pb2.py +18 -0
  221. viam/gen/opentelemetry/proto/resource/v1/resource_pb2.pyi +59 -0
  222. viam/gen/opentelemetry/proto/trace/__init__.py +0 -0
  223. viam/gen/opentelemetry/proto/trace/v1/__init__.py +0 -0
  224. viam/gen/opentelemetry/proto/trace/v1/trace_grpc.py +0 -0
  225. viam/gen/opentelemetry/proto/trace/v1/trace_pb2.py +37 -0
  226. viam/gen/opentelemetry/proto/trace/v1/trace_pb2.pyi +402 -0
  227. viam/gen/proto/rpc/examples/echo/v1/echo_grpc.py +12 -0
  228. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +25 -22
  229. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.pyi +13 -17
  230. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_grpc.py +12 -0
  231. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +23 -20
  232. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.pyi +13 -17
  233. viam/gen/proto/rpc/v1/auth_grpc.py +11 -0
  234. viam/gen/proto/rpc/v1/auth_pb2.py +27 -24
  235. viam/gen/proto/rpc/v1/auth_pb2.pyi +12 -16
  236. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +35 -32
  237. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.pyi +37 -41
  238. viam/gen/proto/rpc/webrtc/v1/signaling_grpc.py +15 -0
  239. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +62 -57
  240. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.pyi +78 -69
  241. viam/gen/provisioning/__init__.py +0 -0
  242. viam/gen/provisioning/v1/__init__.py +0 -0
  243. viam/gen/provisioning/v1/provisioning_grpc.py +59 -0
  244. viam/gen/provisioning/v1/provisioning_pb2.py +45 -0
  245. viam/gen/provisioning/v1/provisioning_pb2.pyi +229 -0
  246. viam/gen/robot/v1/robot_grpc.py +144 -15
  247. viam/gen/robot/v1/robot_pb2.py +193 -119
  248. viam/gen/robot/v1/robot_pb2.pyi +565 -137
  249. viam/gen/service/datamanager/v1/data_manager_grpc.py +20 -2
  250. viam/gen/service/datamanager/v1/data_manager_pb2.py +27 -17
  251. viam/gen/service/datamanager/v1/data_manager_pb2.pyi +52 -10
  252. viam/gen/service/discovery/__init__.py +0 -0
  253. viam/gen/service/discovery/v1/__init__.py +0 -0
  254. viam/gen/service/discovery/v1/discovery_grpc.py +39 -0
  255. viam/gen/service/discovery/v1/discovery_pb2.py +29 -0
  256. viam/gen/service/discovery/v1/discovery_pb2.pyi +51 -0
  257. viam/gen/service/generic/__init__.py +0 -0
  258. viam/gen/service/generic/v1/__init__.py +0 -0
  259. viam/gen/service/generic/v1/generic_grpc.py +29 -0
  260. viam/gen/service/generic/v1/generic_pb2.py +21 -0
  261. viam/gen/service/generic/v1/generic_pb2.pyi +6 -0
  262. viam/gen/service/mlmodel/v1/mlmodel_grpc.py +9 -0
  263. viam/gen/service/mlmodel/v1/mlmodel_pb2.py +76 -29
  264. viam/gen/service/mlmodel/v1/mlmodel_pb2.pyi +307 -28
  265. viam/gen/service/motion/v1/motion_grpc.py +42 -4
  266. viam/gen/service/motion/v1/motion_pb2.py +119 -51
  267. viam/gen/service/motion/v1/motion_pb2.pyi +595 -120
  268. viam/gen/service/navigation/v1/navigation_grpc.py +49 -1
  269. viam/gen/service/navigation/v1/navigation_pb2.py +76 -51
  270. viam/gen/service/navigation/v1/navigation_pb2.pyi +188 -33
  271. viam/gen/service/sensors/v1/sensors_grpc.py +12 -0
  272. viam/gen/service/sensors/v1/sensors_pb2.py +60 -29
  273. viam/gen/service/sensors/v1/sensors_pb2.pyi +18 -21
  274. viam/gen/service/shell/v1/shell_grpc.py +27 -1
  275. viam/gen/service/shell/v1/shell_pb2.py +37 -15
  276. viam/gen/service/shell/v1/shell_pb2.pyi +260 -7
  277. viam/gen/service/slam/v1/slam_grpc.py +24 -2
  278. viam/gen/service/slam/v1/slam_pb2.py +44 -30
  279. viam/gen/service/slam/v1/slam_pb2.pyi +128 -27
  280. viam/gen/service/video/__init__.py +0 -0
  281. viam/gen/service/video/v1/__init__.py +0 -0
  282. viam/gen/service/video/v1/video_grpc.py +39 -0
  283. viam/gen/service/video/v1/video_pb2.py +29 -0
  284. viam/gen/service/video/v1/video_pb2.pyi +72 -0
  285. viam/gen/service/vision/v1/vision_grpc.py +39 -1
  286. viam/gen/service/vision/v1/vision_pb2.py +61 -45
  287. viam/gen/service/vision/v1/vision_pb2.pyi +180 -41
  288. viam/gen/service/worldstatestore/__init__.py +0 -0
  289. viam/gen/service/worldstatestore/v1/__init__.py +0 -0
  290. viam/gen/service/worldstatestore/v1/world_state_store_grpc.py +55 -0
  291. viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +39 -0
  292. viam/gen/service/worldstatestore/v1/world_state_store_pb2.pyi +171 -0
  293. viam/gen/stream/__init__.py +0 -0
  294. viam/gen/stream/v1/__init__.py +0 -0
  295. viam/gen/stream/v1/stream_grpc.py +59 -0
  296. viam/gen/stream/v1/stream_pb2.py +39 -0
  297. viam/gen/stream/v1/stream_pb2.pyi +161 -0
  298. viam/gen/tagger/v1/tagger_pb2.py +9 -8
  299. viam/logging.py +160 -17
  300. viam/media/__init__.py +0 -9
  301. viam/media/audio.py +22 -10
  302. viam/media/utils/__init__.py +0 -0
  303. viam/media/utils/pil/__init__.py +55 -0
  304. viam/media/{viam_rgba_plugin.py → utils/pil/viam_rgba_plugin.py} +10 -16
  305. viam/media/viam_rgba.py +10 -0
  306. viam/media/video.py +197 -73
  307. viam/module/module.py +191 -44
  308. viam/module/resource_data_consumer.py +41 -0
  309. viam/module/service.py +9 -1
  310. viam/module/types.py +4 -5
  311. viam/operations.py +4 -3
  312. viam/proto/app/__init__.py +361 -5
  313. viam/proto/app/agent/__init__.py +28 -0
  314. viam/proto/app/billing.py +51 -27
  315. viam/proto/app/cloudslam/__init__.py +48 -0
  316. viam/proto/app/data/__init__.py +103 -17
  317. viam/proto/app/datapipelines/__init__.py +56 -0
  318. viam/proto/app/dataset/__init__.py +40 -0
  319. viam/proto/app/datasync/__init__.py +11 -5
  320. viam/proto/app/end_user.py +34 -0
  321. viam/proto/app/mlinference/__init__.py +15 -0
  322. viam/proto/app/mltraining/__init__.py +25 -1
  323. viam/proto/app/packages/__init__.py +3 -3
  324. viam/proto/app/robot.py +19 -1
  325. viam/proto/common/__init__.py +35 -8
  326. viam/proto/component/arm/__init__.py +9 -1
  327. viam/proto/component/audioin/__init__.py +16 -0
  328. viam/proto/component/audioinput/__init__.py +3 -1
  329. viam/proto/component/audioout/__init__.py +15 -0
  330. viam/proto/component/base/__init__.py +7 -1
  331. viam/proto/component/board/__init__.py +13 -5
  332. viam/proto/component/button/__init__.py +15 -0
  333. viam/proto/component/camera/__init__.py +9 -1
  334. viam/proto/component/encoder/__init__.py +3 -1
  335. viam/proto/component/gantry/__init__.py +7 -1
  336. viam/proto/component/generic/__init__.py +3 -1
  337. viam/proto/component/gripper/__init__.py +7 -1
  338. viam/proto/component/inputcontroller/__init__.py +7 -1
  339. viam/proto/component/motor/__init__.py +7 -1
  340. viam/proto/component/movementsensor/__init__.py +7 -1
  341. viam/proto/component/posetracker/__init__.py +7 -1
  342. viam/proto/component/powersensor/__init__.py +30 -0
  343. viam/proto/component/sensor/__init__.py +3 -4
  344. viam/proto/component/servo/__init__.py +3 -1
  345. viam/proto/component/switch/__init__.py +26 -0
  346. viam/proto/component/testecho/__init__.py +3 -1
  347. viam/proto/module/__init__.py +3 -1
  348. viam/proto/opentelemetry/__init__.py +0 -0
  349. viam/proto/opentelemetry/proto/__init__.py +0 -0
  350. viam/proto/opentelemetry/proto/common/__init__.py +15 -0
  351. viam/proto/opentelemetry/proto/resource/__init__.py +10 -0
  352. viam/proto/opentelemetry/proto/trace/__init__.py +15 -0
  353. viam/proto/provisioning/__init__.py +42 -0
  354. viam/proto/robot/__init__.py +57 -9
  355. viam/proto/rpc/auth.py +11 -1
  356. viam/proto/rpc/examples/echo/__init__.py +3 -1
  357. viam/proto/rpc/examples/echoresource/__init__.py +7 -1
  358. viam/proto/rpc/webrtc/grpc.py +3 -1
  359. viam/proto/rpc/webrtc/signaling.py +5 -1
  360. viam/proto/service/datamanager/__init__.py +15 -2
  361. viam/proto/service/discovery/__init__.py +15 -0
  362. viam/proto/service/generic/__init__.py +12 -0
  363. viam/proto/service/mlmodel/__init__.py +27 -1
  364. viam/proto/service/motion/__init__.py +35 -5
  365. viam/proto/service/navigation/__init__.py +19 -1
  366. viam/proto/service/sensors/__init__.py +3 -1
  367. viam/proto/service/shell/__init__.py +25 -2
  368. viam/proto/service/slam/__init__.py +13 -1
  369. viam/proto/service/video/__init__.py +15 -0
  370. viam/proto/service/vision/__init__.py +11 -1
  371. viam/proto/service/worldstatestore/__init__.py +32 -0
  372. viam/proto/stream/__init__.py +36 -0
  373. viam/py.typed +0 -0
  374. viam/resource/base.py +45 -8
  375. viam/resource/easy_resource.py +149 -0
  376. viam/resource/manager.py +35 -14
  377. viam/resource/registry.py +40 -52
  378. viam/resource/rpc_client_base.py +33 -1
  379. viam/resource/rpc_service_base.py +15 -8
  380. viam/resource/types.py +39 -26
  381. viam/robot/client.py +458 -91
  382. viam/robot/service.py +13 -107
  383. viam/rpc/dial.py +133 -15
  384. viam/rpc/libviam_rust_utils.so +0 -0
  385. viam/rpc/server.py +59 -15
  386. viam/rpc/types.py +2 -4
  387. viam/services/discovery/__init__.py +12 -0
  388. viam/services/discovery/client.py +55 -0
  389. viam/services/discovery/discovery.py +52 -0
  390. viam/services/discovery/service.py +43 -0
  391. viam/services/generic/__init__.py +18 -0
  392. viam/services/generic/client.py +58 -0
  393. viam/services/generic/generic.py +58 -0
  394. viam/services/generic/service.py +29 -0
  395. viam/services/mlmodel/__init__.py +15 -1
  396. viam/services/mlmodel/client.py +20 -15
  397. viam/services/mlmodel/mlmodel.py +44 -7
  398. viam/services/mlmodel/service.py +9 -13
  399. viam/services/mlmodel/utils.py +101 -0
  400. viam/services/motion/__init__.py +15 -3
  401. viam/services/motion/client.py +109 -150
  402. viam/services/motion/motion.py +380 -0
  403. viam/services/motion/service.py +132 -0
  404. viam/services/navigation/__init__.py +11 -0
  405. viam/services/navigation/client.py +99 -0
  406. viam/services/navigation/navigation.py +250 -0
  407. viam/services/navigation/service.py +137 -0
  408. viam/services/service_base.py +43 -4
  409. viam/services/service_client_base.py +4 -4
  410. viam/services/slam/__init__.py +4 -1
  411. viam/services/slam/client.py +21 -11
  412. viam/services/slam/service.py +16 -19
  413. viam/services/slam/slam.py +66 -5
  414. viam/services/vision/__init__.py +8 -0
  415. viam/services/vision/client.py +115 -111
  416. viam/services/vision/service.py +143 -0
  417. viam/services/vision/vision.py +317 -0
  418. viam/services/worldstatestore/__init__.py +18 -0
  419. viam/services/worldstatestore/client.py +94 -0
  420. viam/services/worldstatestore/service.py +55 -0
  421. viam/services/worldstatestore/worldstatestore.py +90 -0
  422. viam/sessions_client.py +254 -0
  423. viam/streams.py +44 -0
  424. viam/utils.py +143 -15
  425. viam/version_metadata.py +4 -0
  426. viam_sdk-0.66.0.dist-info/METADATA +157 -0
  427. viam_sdk-0.66.0.dist-info/RECORD +531 -0
  428. {viam_sdk-0.3.0.dist-info → viam_sdk-0.66.0.dist-info}/WHEEL +1 -1
  429. viam/components/audio_input/__init__.py +0 -18
  430. viam/components/audio_input/audio_input.py +0 -79
  431. viam/components/audio_input/client.py +0 -60
  432. viam/components/audio_input/service.py +0 -118
  433. viam/components/types.py +0 -5
  434. viam/gen/app/model/v1/model_grpc.py +0 -39
  435. viam/gen/app/model/v1/model_pb2.py +0 -71
  436. viam/gen/app/model/v1/model_pb2.pyi +0 -285
  437. viam/gen/proto/rpc/examples/fileupload/v1/fileupload_grpc.py +0 -21
  438. viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.py +0 -18
  439. viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.pyi +0 -49
  440. viam/media/media.py +0 -53
  441. viam/proto/app/model/__init__.py +0 -40
  442. viam/proto/rpc/examples/fileupload/__init__.py +0 -13
  443. viam/services/sensors/__init__.py +0 -5
  444. viam/services/sensors/client.py +0 -63
  445. viam_sdk-0.3.0.dist-info/LICENSE +0 -202
  446. viam_sdk-0.3.0.dist-info/METADATA +0 -122
  447. viam_sdk-0.3.0.dist-info/RECORD +0 -372
  448. /viam/{gen/app/model → app}/__init__.py +0 -0
  449. /viam/gen/app/{model/v1 → agent}/__init__.py +0 -0
  450. /viam/gen/{proto/rpc/examples/fileupload → app/agent/v1}/__init__.py +0 -0
  451. /viam/gen/{proto/rpc/examples/fileupload/v1 → app/cloudslam}/__init__.py +0 -0
  452. /LICENSE → /viam_sdk-0.66.0.dist-info/licenses/LICENSE +0 -0
viam/app/app_client.py ADDED
@@ -0,0 +1,2696 @@
1
+ import json
2
+ from datetime import datetime
3
+ from enum import Enum
4
+ from typing import Any, AsyncIterator, List, Literal, Mapping, Optional, Tuple, Union
5
+
6
+ from grpclib.client import Channel
7
+ from typing_extensions import Self
8
+
9
+ from viam import logging
10
+ from viam.app._logs import _LogsStream, _LogsStreamWithIterator
11
+ from viam.proto.app import (
12
+ AddRoleRequest,
13
+ APIKeyWithAuthorizations,
14
+ AppServiceStub,
15
+ AuthenticatorInfo,
16
+ Authorization,
17
+ AuthorizedPermissions,
18
+ ChangeRoleRequest,
19
+ CheckPermissionsRequest,
20
+ CheckPermissionsResponse,
21
+ CreateFragmentRequest,
22
+ CreateFragmentResponse,
23
+ CreateKeyFromExistingKeyAuthorizationsRequest,
24
+ CreateKeyFromExistingKeyAuthorizationsResponse,
25
+ CreateKeyRequest,
26
+ CreateKeyResponse,
27
+ CreateLocationRequest,
28
+ CreateLocationResponse,
29
+ CreateLocationSecretRequest,
30
+ CreateLocationSecretResponse,
31
+ CreateModuleRequest,
32
+ CreateModuleResponse,
33
+ CreateOrganizationInviteRequest,
34
+ CreateOrganizationInviteResponse,
35
+ CreateOrganizationRequest,
36
+ CreateOrganizationResponse,
37
+ CreateRegistryItemRequest,
38
+ CreateRobotPartSecretRequest,
39
+ CreateRobotPartSecretResponse,
40
+ DeleteFragmentRequest,
41
+ DeleteKeyRequest,
42
+ DeleteLocationRequest,
43
+ DeleteLocationSecretRequest,
44
+ DeleteOrganizationInviteRequest,
45
+ DeleteOrganizationMemberRequest,
46
+ DeleteOrganizationRequest,
47
+ DeleteRegistryItemRequest,
48
+ DeleteRobotPartRequest,
49
+ DeleteRobotPartSecretRequest,
50
+ DeleteRobotRequest,
51
+ GetFragmentHistoryRequest,
52
+ GetFragmentHistoryResponse,
53
+ GetFragmentRequest,
54
+ GetFragmentResponse,
55
+ GetLocationMetadataRequest,
56
+ GetLocationMetadataResponse,
57
+ GetLocationRequest,
58
+ GetLocationResponse,
59
+ GetModuleRequest,
60
+ GetModuleResponse,
61
+ GetOrganizationMetadataRequest,
62
+ GetOrganizationMetadataResponse,
63
+ GetOrganizationNamespaceAvailabilityRequest,
64
+ GetOrganizationNamespaceAvailabilityResponse,
65
+ GetOrganizationRequest,
66
+ GetOrganizationResponse,
67
+ GetOrganizationsWithAccessToLocationRequest,
68
+ GetOrganizationsWithAccessToLocationResponse,
69
+ GetRegistryItemRequest,
70
+ GetRegistryItemResponse,
71
+ GetRobotAPIKeysRequest,
72
+ GetRobotAPIKeysResponse,
73
+ GetRobotMetadataRequest,
74
+ GetRobotMetadataResponse,
75
+ GetRobotPartHistoryRequest,
76
+ GetRobotPartHistoryResponse,
77
+ GetRobotPartLogsRequest,
78
+ GetRobotPartLogsResponse,
79
+ GetRobotPartMetadataRequest,
80
+ GetRobotPartMetadataResponse,
81
+ GetRobotPartRequest,
82
+ GetRobotPartResponse,
83
+ GetRobotPartsRequest,
84
+ GetRobotPartsResponse,
85
+ GetRobotRequest,
86
+ GetRobotResponse,
87
+ GetRoverRentalRobotsRequest,
88
+ GetRoverRentalRobotsResponse,
89
+ GetUserIDByEmailRequest,
90
+ GetUserIDByEmailResponse,
91
+ ListAuthorizationsRequest,
92
+ ListAuthorizationsResponse,
93
+ ListFragmentsRequest,
94
+ ListFragmentsResponse,
95
+ ListKeysRequest,
96
+ ListKeysResponse,
97
+ ListLocationsRequest,
98
+ ListLocationsResponse,
99
+ ListModulesRequest,
100
+ ListModulesResponse,
101
+ ListOrganizationMembersRequest,
102
+ ListOrganizationMembersResponse,
103
+ ListOrganizationsByUserRequest,
104
+ ListOrganizationsByUserResponse,
105
+ ListOrganizationsRequest,
106
+ ListOrganizationsResponse,
107
+ ListRegistryItemsRequest,
108
+ ListRegistryItemsResponse,
109
+ ListRobotsRequest,
110
+ ListRobotsResponse,
111
+ Location,
112
+ LocationAuth,
113
+ LocationAuthRequest,
114
+ LocationAuthResponse,
115
+ MarkPartAsMainRequest,
116
+ MarkPartForRestartRequest,
117
+ Model,
118
+ Module,
119
+ ModuleFileInfo,
120
+ NewRobotPartRequest,
121
+ NewRobotPartResponse,
122
+ NewRobotRequest,
123
+ NewRobotResponse,
124
+ Organization,
125
+ OrganizationIdentity,
126
+ OrganizationInvite,
127
+ OrganizationMember,
128
+ OrgDetails,
129
+ RegistryItem,
130
+ RegistryItemStatus,
131
+ RemoveRoleRequest,
132
+ ResendOrganizationInviteRequest,
133
+ ResendOrganizationInviteResponse,
134
+ Robot,
135
+ RotateKeyRequest,
136
+ RotateKeyResponse,
137
+ RoverRentalRobot,
138
+ SharedSecret,
139
+ ShareLocationRequest,
140
+ TailRobotPartLogsRequest,
141
+ TailRobotPartLogsResponse,
142
+ UnshareLocationRequest,
143
+ UpdateFragmentRequest,
144
+ UpdateFragmentResponse,
145
+ UpdateLocationMetadataRequest,
146
+ UpdateLocationMetadataResponse,
147
+ UpdateLocationRequest,
148
+ UpdateLocationResponse,
149
+ UpdateModuleRequest,
150
+ UpdateModuleResponse,
151
+ UpdateOrganizationInviteAuthorizationsRequest,
152
+ UpdateOrganizationInviteAuthorizationsResponse,
153
+ UpdateOrganizationMetadataRequest,
154
+ UpdateOrganizationMetadataResponse,
155
+ UpdateOrganizationRequest,
156
+ UpdateOrganizationResponse,
157
+ UpdateRegistryItemRequest,
158
+ UpdateRobotMetadataRequest,
159
+ UpdateRobotMetadataResponse,
160
+ UpdateRobotPartMetadataRequest,
161
+ UpdateRobotPartMetadataResponse,
162
+ UpdateRobotPartRequest,
163
+ UpdateRobotPartResponse,
164
+ UpdateRobotRequest,
165
+ UpdateRobotResponse,
166
+ UploadModuleFileRequest,
167
+ Visibility,
168
+ )
169
+ from viam.proto.app import Fragment as FragmentPB
170
+ from viam.proto.app import FragmentHistoryEntry as FragmentHistoryEntryPB
171
+ from viam.proto.app import FragmentVisibility as FragmentVisibilityPB
172
+ from viam.proto.app import RobotPart as RobotPartPB
173
+ from viam.proto.app import RobotPartHistoryEntry as RobotPartHistoryEntryPB
174
+ from viam.proto.app.packages import PackageType
175
+ from viam.proto.common import LogEntry as LogEntryPB
176
+ from viam.utils import datetime_to_timestamp, dict_to_struct, struct_to_dict
177
+
178
+ LOGGER = logging.getLogger(__name__)
179
+
180
+
181
+ class RobotPart:
182
+ """A class that mirrors the `RobotPart` proto message.
183
+
184
+ Use this class to make the attributes of a `viam.proto.app.RobotPart` more accessible and easier to read/interpret.
185
+ """
186
+
187
+ @classmethod
188
+ def from_proto(cls, robot_part: RobotPartPB) -> Self:
189
+ """Create a `RobotPart` from the .proto defined `RobotPart`.
190
+
191
+ Args:
192
+ robot_part (viam.proto.app.RobotPart): The object to copy from.
193
+
194
+ Returns:
195
+ RobotPart: The `RobotPart`.
196
+ """
197
+ self = cls()
198
+ self.id = robot_part.id
199
+ self.name = robot_part.name
200
+ self.dns_name = robot_part.dns_name
201
+ self.secret = robot_part.secret
202
+ self.robot = robot_part.robot
203
+ self.location_id = robot_part.location_id
204
+ self.robot_config = struct_to_dict(robot_part.robot_config) if robot_part.HasField("robot_config") else None
205
+ self.last_access = robot_part.last_access.ToDatetime() if robot_part.HasField("last_access") else None
206
+ self.user_supplied_info = struct_to_dict(robot_part.user_supplied_info) if robot_part.HasField("user_supplied_info") else None
207
+ self.main_part = robot_part.main_part
208
+ self.fqdn = robot_part.fqdn
209
+ self.local_fqdn = robot_part.local_fqdn
210
+ self.created_on = robot_part.created_on.ToDatetime() if robot_part.HasField("created_on") else None
211
+ self.secrets = list(robot_part.secrets)
212
+ self.last_updated = robot_part.last_updated.ToDatetime() if robot_part.HasField("last_updated") else None
213
+ return self
214
+
215
+ id: str
216
+ name: str
217
+ dns_name: str
218
+ secret: str
219
+ robot: str
220
+ location_id: str
221
+ robot_config: Optional[Mapping[str, Any]]
222
+ last_access: Optional[datetime]
223
+ user_supplied_info: Optional[Mapping[str, Any]]
224
+ main_part: bool
225
+ fqdn: str
226
+ local_fqdn: str
227
+ created_on: Optional[datetime]
228
+ secrets: Optional[List[SharedSecret]]
229
+ last_updated: Optional[datetime]
230
+
231
+ @property
232
+ def proto(self) -> RobotPartPB:
233
+ return RobotPartPB(
234
+ id=self.id,
235
+ name=self.name,
236
+ dns_name=self.dns_name,
237
+ secret=self.secret,
238
+ robot=self.robot,
239
+ location_id=self.location_id,
240
+ robot_config=dict_to_struct(self.robot_config) if self.robot_config else None,
241
+ last_access=datetime_to_timestamp(self.last_access) if self.last_access else None,
242
+ user_supplied_info=dict_to_struct(self.user_supplied_info) if self.user_supplied_info else None,
243
+ main_part=self.main_part,
244
+ fqdn=self.fqdn,
245
+ local_fqdn=self.local_fqdn,
246
+ created_on=datetime_to_timestamp(self.created_on) if self.created_on else None,
247
+ secrets=self.secrets,
248
+ last_updated=datetime_to_timestamp(self.last_updated) if self.last_updated else None,
249
+ )
250
+
251
+
252
+ class LogEntry:
253
+ """A class that mirrors the `LogEntry` proto message.
254
+
255
+ Use this class to make the attributes of a `viam.proto.app.LogEntry` more accessible and easier to read/interpret.
256
+ """
257
+
258
+ @classmethod
259
+ def from_proto(cls, log_entry: LogEntryPB) -> Self:
260
+ """Create a `LogEntry` from the .proto defined `LogEntry`.
261
+
262
+ Args:
263
+ log_entry (viam.proto.app.LogEntry): The object to copy from.
264
+
265
+ Returns:
266
+ LogEntry: The `LogEntry`.
267
+ """
268
+ self = cls()
269
+ self.host = log_entry.host
270
+ self.level = log_entry.level
271
+ self.time = log_entry.time.ToDatetime() if log_entry.HasField("time") else None
272
+ self.logger_name = log_entry.logger_name
273
+ self.message = log_entry.message
274
+ self.caller = struct_to_dict(log_entry.caller) if log_entry.HasField("caller") else None
275
+ self.stack = log_entry.stack
276
+ self.fields = [struct_to_dict(field) for field in log_entry.fields]
277
+ return self
278
+
279
+ host: str
280
+ level: str
281
+ time: Optional[datetime]
282
+ logger_name: str
283
+ message: str
284
+ caller: Optional[Mapping[str, Any]]
285
+ stack: str
286
+ fields: Optional[List[Mapping[str, Any]]]
287
+
288
+ @property
289
+ def proto(self) -> LogEntryPB:
290
+ return LogEntryPB(
291
+ host=self.host,
292
+ level=self.level,
293
+ time=datetime_to_timestamp(self.time) if self.time else None,
294
+ logger_name=self.logger_name,
295
+ message=self.message,
296
+ caller=dict_to_struct(self.caller) if self.caller else None,
297
+ stack=self.stack,
298
+ fields=[dict_to_struct(field) for field in self.fields] if self.fields else None,
299
+ )
300
+
301
+
302
+ class Fragment:
303
+ """A class that mirrors the `Fragment` proto message.
304
+
305
+ Use this class to make the attributes of a `viam.proto.app.RobotPart` more accessible and easier to read/interpret.
306
+ """
307
+
308
+ class Visibility(str, Enum):
309
+ """
310
+ FragmentVisibility specifies who is permitted to view the fragment.
311
+ """
312
+
313
+ PRIVATE = "private"
314
+ """
315
+ Only visible to members in the fragment's organization.
316
+ """
317
+
318
+ PUBLIC = "public"
319
+ """
320
+ Visible to anyone and appears on the fragments page.
321
+ """
322
+
323
+ PUBLIC_UNLISTED = "public_unlisted"
324
+ """
325
+ Visible to anyone but does not appear on the fragments page.
326
+ """
327
+
328
+ UNSPECIFIED = "unspecified"
329
+ """
330
+ Uninitialized visibility.
331
+ """
332
+
333
+ @classmethod
334
+ def from_proto(cls, visibility: FragmentVisibilityPB.ValueType) -> "Fragment.Visibility":
335
+ if visibility == FragmentVisibilityPB.FRAGMENT_VISIBILITY_PRIVATE:
336
+ return Fragment.Visibility.PRIVATE
337
+ if visibility == FragmentVisibilityPB.FRAGMENT_VISIBILITY_PUBLIC:
338
+ return Fragment.Visibility.PUBLIC
339
+ if visibility == FragmentVisibilityPB.FRAGMENT_VISIBILITY_PUBLIC_UNLISTED:
340
+ return Fragment.Visibility.PUBLIC_UNLISTED
341
+ return Fragment.Visibility.UNSPECIFIED
342
+
343
+ def to_proto(self) -> FragmentVisibilityPB.ValueType:
344
+ if self == self.PRIVATE:
345
+ return FragmentVisibilityPB.FRAGMENT_VISIBILITY_PRIVATE
346
+ if self == self.PUBLIC:
347
+ return FragmentVisibilityPB.FRAGMENT_VISIBILITY_PUBLIC
348
+ if self == self.PUBLIC_UNLISTED:
349
+ return FragmentVisibilityPB.FRAGMENT_VISIBILITY_PUBLIC_UNLISTED
350
+ return FragmentVisibilityPB.FRAGMENT_VISIBILITY_UNSPECIFIED
351
+
352
+ @classmethod
353
+ def from_proto(cls, fragment: FragmentPB) -> Self:
354
+ """Create a `Fragment` from the .proto defined `Fragment`.
355
+
356
+ Args:
357
+ fragment (viam.proto.app.Fragment): The object to copy from.
358
+
359
+ Returns:
360
+ Fragment: The `Fragment`.
361
+ """
362
+ self = cls()
363
+ self.id = fragment.id
364
+ self.name = fragment.name
365
+ self.fragment = struct_to_dict(fragment.fragment) if fragment.HasField("fragment") else None
366
+ self.organization_owner = fragment.organization_owner
367
+ self.public = fragment.public
368
+ self.created_on = fragment.created_on.ToDatetime() if fragment.HasField("created_on") else None
369
+ self.organization_name = fragment.organization_name
370
+ self.robot_part_count = fragment.robot_part_count
371
+ self.organization_count = fragment.organization_count
372
+ self.only_used_by_owner = fragment.only_used_by_owner
373
+ self.visibility = Fragment.Visibility.from_proto(fragment.visibility)
374
+ self.last_updated = fragment.last_updated.ToDatetime() if fragment.HasField("last_updated") else None
375
+ return self
376
+
377
+ id: str
378
+ name: str
379
+ fragment: Optional[Mapping[str, Any]]
380
+ organization_owner: str
381
+ public: bool
382
+ created_on: Optional[datetime]
383
+ organization_name: str
384
+ robot_part_count: int
385
+ organization_count: int
386
+ only_used_by_owner: bool
387
+ visibility: Visibility
388
+ last_updated: Optional[datetime]
389
+
390
+ @property
391
+ def proto(self) -> FragmentPB:
392
+ return FragmentPB(
393
+ id=self.id,
394
+ name=self.name,
395
+ fragment=dict_to_struct(self.fragment) if self.fragment else None,
396
+ organization_owner=self.organization_owner,
397
+ public=self.public,
398
+ created_on=datetime_to_timestamp(self.created_on) if self.created_on else None,
399
+ organization_name=self.organization_name,
400
+ robot_part_count=self.robot_part_count,
401
+ organization_count=self.organization_count,
402
+ only_used_by_owner=self.only_used_by_owner,
403
+ visibility=self.visibility.to_proto(),
404
+ last_updated=datetime_to_timestamp(self.last_updated) if self.last_updated else None,
405
+ )
406
+
407
+
408
+ class FragmentHistoryEntry:
409
+ """A class that mirrors the `FragmentHistoryEntry` proto message.
410
+
411
+ Use this class to make the attributes of a `viam.proto.app.FragmentHistoryEntry` more accessible and easier to read/interpret.
412
+ """
413
+
414
+ @classmethod
415
+ def from_proto(cls, fragment_history_entry: FragmentHistoryEntryPB) -> Self:
416
+ """Create a `FragmentHistoryEntry` from the .proto defined `FragmentHistoryEntry`.
417
+
418
+ Args:
419
+ fragment_history_entry (viam.proto.app.FragmentHistoryEntry): The object to copy from.
420
+
421
+ Returns:
422
+ FragmentHistoryEntry: The `FragmentHistoryEntry`.
423
+ """
424
+ self = cls()
425
+ self.fragment = fragment_history_entry.fragment
426
+ self.edited_on = fragment_history_entry.edited_on.ToDatetime()
427
+ self.old = Fragment.from_proto(fragment_history_entry.old)
428
+ self.edited_by = fragment_history_entry.edited_by
429
+ return self
430
+
431
+ fragment: str
432
+ edited_on: datetime
433
+ old: Fragment
434
+ edited_by: AuthenticatorInfo
435
+
436
+ @property
437
+ def proto(self) -> FragmentHistoryEntryPB:
438
+ return FragmentHistoryEntryPB(
439
+ fragment=self.fragment,
440
+ edited_on=datetime_to_timestamp(self.edited_on),
441
+ edited_by=self.edited_by,
442
+ old=self.old.proto if self.old else None,
443
+ )
444
+
445
+
446
+ class RobotPartHistoryEntry:
447
+ """A class that mirrors the `RobotPartHistoryEntry` proto message.
448
+
449
+ Use this class to make the attributes of a `viam.proto.app.RobotPartHistoryEntry` more accessible and easier to read/interpret.
450
+ """
451
+
452
+ @classmethod
453
+ def from_proto(cls, robot_part_history_entry: RobotPartHistoryEntryPB) -> Self:
454
+ """Create a `RobotPartHistoryEntry` from the .proto defined `RobotPartHistoryEntry`.
455
+
456
+ Args:
457
+ robot_part_history_entry (viam.proto.app.RobotPartHistoryEntry): The object to copy from.
458
+
459
+ Returns:
460
+ RobotPartHistoryEntry: The `RobotPartHistoryEntry`.
461
+ """
462
+ self = cls()
463
+ self.part = robot_part_history_entry.part
464
+ self.robot = robot_part_history_entry.robot
465
+ self.when = robot_part_history_entry.when.ToDatetime() if robot_part_history_entry.HasField("when") else None
466
+ self.old = RobotPart.from_proto(robot_part_history_entry.old) if robot_part_history_entry.HasField("old") else None
467
+ return self
468
+
469
+ part: str
470
+ robot: str
471
+ when: Optional[datetime]
472
+ old: Optional[RobotPart]
473
+
474
+ @property
475
+ def proto(self) -> RobotPartHistoryEntryPB:
476
+ return RobotPartHistoryEntryPB(
477
+ part=self.part,
478
+ robot=self.robot,
479
+ when=datetime_to_timestamp(self.when) if self.when else None,
480
+ old=self.old.proto if self.old else None,
481
+ )
482
+
483
+
484
+ class APIKeyAuthorization:
485
+ """A class with the necessary authorization data for creating an API key.
486
+
487
+ Use this class when constructing API key authorizations to minimize the risk of malformed or missing data.
488
+ """
489
+
490
+ def __init__(
491
+ self,
492
+ role: Union[Literal["owner"], Literal["operator"]],
493
+ resource_type: Union[Literal["organization"], Literal["location"], Literal["robot"]],
494
+ resource_id: str,
495
+ ):
496
+ """role (Union[Literal["owner"], Literal["operator"]]): The role to add.
497
+ resource_type (Union[Literal["organization"], Literal["location"], Literal["robot"]]): Type of the resource to add role to.
498
+ Must match `resource_id`.
499
+ resource_id (str): ID of the resource the role applies to (that is, either an organization, location, or robot ID).
500
+ """
501
+ self._role = role
502
+ self._resource_type = resource_type
503
+ self._resource_id = resource_id
504
+
505
+ _role: str
506
+ _resource_type: str
507
+ _resource_id: str
508
+
509
+
510
+ class AppClient:
511
+ """gRPC client for method calls to app.
512
+
513
+ Constructor is used by `ViamClient` to instantiate relevant service stub. Calls to `AppClient` methods should be made through
514
+ `ViamClient`.
515
+
516
+ Establish a Connection::
517
+
518
+ import asyncio
519
+
520
+ from viam.rpc.dial import DialOptions, Credentials
521
+ from viam.app.viam_client import ViamClient
522
+
523
+
524
+ async def connect() -> ViamClient:
525
+ # Replace "<API-KEY>" (including brackets) with your API key and "<API-KEY-ID>" with your API key ID
526
+ dial_options = DialOptions.with_api_key("<API-KEY>", "<API-KEY-ID>")
527
+ return await ViamClient.create_from_dial_options(dial_options)
528
+
529
+
530
+ async def main():
531
+
532
+ # Make a ViamClient
533
+ async with await connect() as viam_client:
534
+ # Instantiate an AppClient called "cloud" to run cloud app API methods on
535
+ cloud = viam_client.app_client
536
+
537
+ if __name__ == '__main__':
538
+ asyncio.run(main())
539
+
540
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/>`_.
541
+ """
542
+
543
+ def __init__(self, channel: Channel, metadata: Mapping[str, str]):
544
+ """Create an `AppClient` that maintains a connection to app.
545
+
546
+ Args:
547
+ channel (grpclib.client.Channel): connection to app.
548
+ metadata (Mapping[str, str]): Required authorization token to send requests to app.
549
+ """
550
+ self._metadata = metadata
551
+ self._app_client = AppServiceStub(channel)
552
+ self._channel = channel
553
+
554
+ _app_client: AppServiceStub
555
+ _metadata: Mapping[str, str]
556
+ _channel: Channel
557
+ _organization_id: Optional[str] = None
558
+
559
+ async def _create_authorization(
560
+ self,
561
+ organization_id: str,
562
+ identity_id: str,
563
+ identity_type: str,
564
+ role: Union[Literal["owner"], Literal["operator"]],
565
+ resource_type: Union[Literal["organization"], Literal["location"], Literal["robot"]],
566
+ resource_id: str,
567
+ ) -> Authorization:
568
+ return Authorization(
569
+ authorization_type="role",
570
+ identity_id=identity_id,
571
+ identity_type=identity_type,
572
+ authorization_id=f"{resource_type}_{role}",
573
+ resource_type=resource_type,
574
+ resource_id=resource_id,
575
+ organization_id=organization_id,
576
+ )
577
+
578
+ async def _create_authorization_for_new_api_key(self, org_id: str, auth: APIKeyAuthorization) -> Authorization:
579
+ """Creates a new Authorization specifically for creating an API key."""
580
+ return await self._create_authorization(
581
+ organization_id=org_id,
582
+ identity_id="", # setting `identity_id` when creating an API key results in an error
583
+ identity_type="api-key",
584
+ role=auth._role, # type: ignore -- Ignoring because this is technically a `string`
585
+ resource_type=auth._resource_type, # type: ignore -- Ignoring because this is technically a `string`
586
+ resource_id=auth._resource_id,
587
+ )
588
+
589
+ async def get_user_id_by_email(self, email: str) -> str:
590
+ """Get the ID of a user by email.
591
+
592
+ ::
593
+
594
+ id = await cloud.get_user_id_by_email("youremail@email.com")
595
+
596
+ Args:
597
+ email (str): The email of the user.
598
+
599
+ Returns:
600
+ str: The ID of the user.
601
+
602
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getuseridbyemail>`_.
603
+ """
604
+ request = GetUserIDByEmailRequest(email=email)
605
+ response: GetUserIDByEmailResponse = await self._app_client.GetUserIDByEmail(request, metadata=self._metadata)
606
+ return response.user_id
607
+
608
+ async def create_organization(self, name: str) -> Organization:
609
+ """Create an organization.
610
+
611
+ ::
612
+
613
+ organization = await cloud.create_organization("name")
614
+
615
+ Args:
616
+ name (str): The name of the organization.
617
+
618
+ Returns:
619
+ Organization: The created organization.
620
+
621
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createorganization>`_.
622
+ """
623
+ request = CreateOrganizationRequest(name=name)
624
+ response: CreateOrganizationResponse = await self._app_client.CreateOrganization(request, metadata=self._metadata)
625
+ return response.organization
626
+
627
+ async def list_organizations(self) -> List[Organization]:
628
+ """List the organization(s) the user is an authorized owner of.
629
+
630
+ ::
631
+
632
+ org_list = await cloud.list_organizations()
633
+
634
+ Returns:
635
+ List[viam.proto.app.Organization]: The list of organizations.
636
+
637
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listorganizations>`_.
638
+ """
639
+ request = ListOrganizationsRequest()
640
+ response: ListOrganizationsResponse = await self._app_client.ListOrganizations(request, metadata=self._metadata)
641
+ return list(response.organizations)
642
+
643
+ async def get_organizations_with_access_to_location(self, location_id: str) -> List[OrganizationIdentity]:
644
+ """Get all organizations that have access to a location.
645
+
646
+ ::
647
+
648
+ org_list = await cloud.get_organizations_with_access_to_location("location-id")
649
+
650
+ Args:
651
+ location_id (str): The ID of the location.
652
+
653
+ Returns:
654
+ List[viam.proto.app.OrganizationIdentity]: The list of organizations.
655
+
656
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getorganizationswithaccesstolocation>`_.
657
+ """
658
+ request = GetOrganizationsWithAccessToLocationRequest(location_id=location_id)
659
+ response: GetOrganizationsWithAccessToLocationResponse = await self._app_client.GetOrganizationsWithAccessToLocation(
660
+ request, metadata=self._metadata
661
+ )
662
+ return list(response.organization_identities)
663
+
664
+ async def list_organizations_by_user(self, user_id: str) -> List[OrgDetails]:
665
+ """List the organizations a user belongs to.
666
+
667
+ ::
668
+
669
+ org_list = await cloud.list_organizations_by_user("<YOUR-USER-ID>")
670
+
671
+ Args:
672
+ user_id (str): The ID of the user. You can retrieve this with the get_user_id_by_email() method.
673
+
674
+ Returns:
675
+ List[OrgDetails]: The list of organizations.
676
+
677
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listorganizationsbyuser>`_.
678
+ """
679
+ request = ListOrganizationsByUserRequest(user_id=user_id)
680
+ response: ListOrganizationsByUserResponse = await self._app_client.ListOrganizationsByUser(request, metadata=self._metadata)
681
+ return list(response.orgs)
682
+
683
+ async def get_organization(self, org_id: str) -> Organization:
684
+ """Retrieve the organization object for the requested organization containing the organization's ID,
685
+ name, public namespace, and more.
686
+
687
+ ::
688
+
689
+ org = await cloud.get_organization("<YOUR-ORG-ID>")
690
+
691
+ Args:
692
+ org_id (str): The ID of the organization to query. You can retrieve this from the organization settings page.
693
+
694
+ Raises:
695
+ GRPCError: If the provided org_id is invalid, or not currently authed to.
696
+
697
+ Returns:
698
+ viam.proto.app.Organization: The requested organization.
699
+
700
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getorganization>`_.
701
+ """
702
+ request = GetOrganizationRequest(organization_id=org_id)
703
+ response: GetOrganizationResponse = await self._app_client.GetOrganization(request, metadata=self._metadata)
704
+ return response.organization
705
+
706
+ async def get_organization_namespace_availability(self, public_namespace: str) -> bool:
707
+ """Check the availability of an organization namespace.
708
+
709
+ ::
710
+
711
+ available = await cloud.get_organization_namespace_availability(
712
+ public_namespace="my-cool-organization")
713
+
714
+ Args:
715
+ public_namespace (str): Organization namespace to check. Namespaces can only contain lowercase alphanumeric and dash
716
+ characters.
717
+
718
+ Raises:
719
+ GRPCError: If an invalid namespace (for example, "") is provided.
720
+
721
+ Returns:
722
+ bool: True if the provided namespace is available.
723
+
724
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getorganizationnamespaceavailability>`_.
725
+ """
726
+ request = GetOrganizationNamespaceAvailabilityRequest(public_namespace=public_namespace)
727
+ response: GetOrganizationNamespaceAvailabilityResponse = await self._app_client.GetOrganizationNamespaceAvailability(
728
+ request, metadata=self._metadata
729
+ )
730
+ return response.available
731
+
732
+ async def update_organization(
733
+ self,
734
+ org_id: str,
735
+ name: Optional[str] = None,
736
+ public_namespace: Optional[str] = None,
737
+ region: Optional[str] = None,
738
+ cid: Optional[str] = None,
739
+ ) -> Organization:
740
+ """Updates organization details.
741
+
742
+ ::
743
+
744
+ organization = await cloud.update_organization(
745
+ org_id="<YOUR-ORG-ID>",
746
+ name="Artoo's Org",
747
+ public_namespace="artoo"
748
+ )
749
+
750
+ Args:
751
+ org_id (str): The ID of the organization to update.
752
+ name (Optional[str]): If provided, updates the org's name.
753
+ public_namespace (Optional[str]): If provided, sets the org's namespace if it hasn't already been set.
754
+ region (Optional[str]): If provided, updates the org's region.
755
+ cid (Optional[str]): If provided, update's the org's CRM ID.
756
+
757
+ Raises:
758
+ GRPCError: If the org's namespace has already been set, or if the provided namespace is already taken.
759
+
760
+ Returns:
761
+ viam.proto.app.Organization: The updated organization.
762
+
763
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updateorganization>`_.
764
+ """
765
+ request = UpdateOrganizationRequest(
766
+ organization_id=org_id,
767
+ public_namespace=public_namespace,
768
+ region=region,
769
+ cid=cid,
770
+ name=name,
771
+ )
772
+ response: UpdateOrganizationResponse = await self._app_client.UpdateOrganization(request, metadata=self._metadata)
773
+ return response.organization
774
+
775
+ async def delete_organization(self, org_id: str) -> None:
776
+ """Delete an organization
777
+
778
+ ::
779
+
780
+ await cloud.delete_organization("<YOUR-ORG-ID>")
781
+
782
+ Args:
783
+ org_id (str): The ID of the organization.
784
+ You can obtain your organization ID from the organization settings page.
785
+
786
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deleteorganization>`_.
787
+ """
788
+ request = DeleteOrganizationRequest(organization_id=org_id)
789
+ await self._app_client.DeleteOrganization(request, metadata=self._metadata)
790
+
791
+ async def list_organization_members(self, org_id: str) -> Tuple[List[OrganizationMember], List[OrganizationInvite]]:
792
+ """List the members and invites of the currently authed-to organization.
793
+
794
+ ::
795
+
796
+ member_list, invite_list = await cloud.list_organization_members("<YOUR-ORG-ID>")
797
+
798
+ Args:
799
+ org_id (str): The ID of the organization to list members of.
800
+ You can obtain your organization ID from the organization settings page.
801
+
802
+ Returns:
803
+ Tuple[List[viam.proto.app.OrganizationMember], List[viam.proto.app.OrganizationInvite]]: A tuple containing two lists; the first
804
+ [0] of organization members, and the second [1] of organization invites.
805
+
806
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listorganizationmembers>`_.
807
+ """
808
+ request = ListOrganizationMembersRequest(organization_id=org_id)
809
+ response: ListOrganizationMembersResponse = await self._app_client.ListOrganizationMembers(request, metadata=self._metadata)
810
+ return list(response.members), list(response.invites)
811
+
812
+ async def create_organization_invite(
813
+ self,
814
+ org_id: str,
815
+ email: str,
816
+ authorizations: Optional[List[Authorization]] = None,
817
+ send_email_invite: bool = True,
818
+ ) -> OrganizationInvite:
819
+ """Creates an organization invite and sends it via email.
820
+
821
+ ::
822
+
823
+ await cloud.create_organization_invite("<YOUR-ORG-ID>", "youremail@email.com")
824
+
825
+ Args:
826
+ org_id (str): The ID of the organization to create an invite for.
827
+ You can obtain your organization ID from the organization settings page.
828
+ email (str): The email address to send the invite to.
829
+ authorizations (Optional[List[viam.proto.app.Authorization]]): Specifications of the
830
+ authorizations to include in the invite. If not provided, full owner permissions will
831
+ be granted.
832
+ send_email_invite (Optional[bool]): Whether or not an email should be sent to the recipient of an invite.
833
+ The user must accept the email to be added to the associated authorizations.
834
+ When set to false, the user automatically receives the associated authorization
835
+ on the next login of the user with the associated email address.
836
+
837
+ Raises:
838
+ GRPCError: if an invalid email is provided, or if the user is already a member of the org.
839
+
840
+ Returns:
841
+ OrganizationInvite: The organization invite.
842
+
843
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createorganizationinvite>`_.
844
+ """
845
+ request = CreateOrganizationInviteRequest(
846
+ organization_id=org_id, email=email, authorizations=authorizations, send_email_invite=send_email_invite
847
+ )
848
+ response: CreateOrganizationInviteResponse = await self._app_client.CreateOrganizationInvite(request, metadata=self._metadata)
849
+ return response.invite
850
+
851
+ async def update_organization_invite_authorizations(
852
+ self,
853
+ org_id: str,
854
+ email: str,
855
+ add_authorizations: Optional[List[Authorization]] = None,
856
+ remove_authorizations: Optional[List[Authorization]] = None,
857
+ ) -> OrganizationInvite:
858
+ """Update the authorizations attached to an organization invite that has already been created.
859
+
860
+ Note that an invite can only have one authorization at each resource (for example, organization, location, robot, etc.) level and
861
+ must have at least one authorization overall.
862
+
863
+ ::
864
+
865
+ from viam.proto.app import Authorization
866
+
867
+ auth = Authorization(
868
+ authorization_type="role",
869
+ authorization_id="location_owner",
870
+ resource_type="location", # "robot", "location", or "organization"
871
+ resource_id="012456lni0", # machine id, location id or org id
872
+ identity_id="",
873
+ organization_id="<YOUR-ORG-ID>",
874
+ identity_type=""
875
+ )
876
+
877
+ update_invite = await cloud.update_organization_invite_authorizations(
878
+ org_id="<YOUR-ORG-ID>",
879
+ email="notarealemail@viam.com",
880
+ add_authorizations=[auth]
881
+ )
882
+
883
+ Args:
884
+ org_id (str): The ID of the organization that the invite is for.
885
+ You can obtain your organization ID from the organization settings page.
886
+ email (str): Email of the user the invite was sent to.
887
+ add_authorizations (Optional[List[viam.proto.app.Authorization]]): Optional list of authorizations to add to the invite.
888
+ remove_authorizations (Optional[List[viam.proto.app.Authorization]]): Optional list of authorizations to remove from the invite.
889
+
890
+ Raises:
891
+ GRPCError: If no authorizations are passed or if an invalid combination of authorizations is passed (for example an
892
+ authorization to remove when the invite only contains one authorization).
893
+
894
+ Returns:
895
+ viam.proto.app.OrganizationInvite: The updated invite.
896
+
897
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updateorganizationinviteauthorizations>`_.
898
+ """
899
+ request = UpdateOrganizationInviteAuthorizationsRequest(
900
+ organization_id=org_id, email=email, add_authorizations=add_authorizations, remove_authorizations=remove_authorizations
901
+ )
902
+ response: UpdateOrganizationInviteAuthorizationsResponse = await self._app_client.UpdateOrganizationInviteAuthorizations(
903
+ request, metadata=self._metadata
904
+ )
905
+ return response.invite
906
+
907
+ async def delete_organization_member(self, org_id: str, user_id: str) -> None:
908
+ """Remove a member from the organization.
909
+
910
+ ::
911
+
912
+ member_list, invite_list = await cloud.list_organization_members(org_id="<YOUR-ORG-ID>")
913
+ first_user_id = member_list[0].user_id
914
+
915
+ await cloud.delete_organization_member(org_id="org_id", user_id=first_user_id)
916
+
917
+ Args:
918
+ org_id (str): The ID of the org to remove the user from.
919
+ You can obtain your organization ID from the organization settings page.
920
+ user_id (str): The ID of the user to remove.
921
+
922
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deleteorganizationmember>`_.
923
+ """
924
+ request = DeleteOrganizationMemberRequest(organization_id=org_id, user_id=user_id)
925
+ await self._app_client.DeleteOrganizationMember(request, metadata=self._metadata)
926
+
927
+ async def delete_organization_invite(self, org_id: str, email: str) -> None:
928
+ """Deletes a pending organization invite.
929
+
930
+ ::
931
+
932
+ await cloud.delete_organization_invite("<YOUR-ORG-ID>", "youremail@email.com")
933
+
934
+ Args:
935
+ org_id (str): The ID of the organization that the invite to delete was for.
936
+ You can obtain your organization ID from the organization settings page.
937
+ email (str): The email address the pending invite was sent to.
938
+
939
+ Raises:
940
+ GRPCError: If no pending invite is associated with the provided email address.
941
+
942
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deleteorganizationinvite>`_.
943
+ """
944
+ request = DeleteOrganizationInviteRequest(organization_id=org_id, email=email)
945
+ await self._app_client.DeleteOrganizationInvite(request, metadata=self._metadata)
946
+
947
+ async def resend_organization_invite(self, org_id: str, email: str) -> OrganizationInvite:
948
+ """Re-sends a pending organization invite email.
949
+
950
+ ::
951
+
952
+ org_invite = await cloud.resend_organization_invite("<YOUR-ORG-ID>", "youremail@email.com")
953
+
954
+ Args:
955
+ org_id (str): The ID of the organization that the invite to resend was for.
956
+ You can obtain your organization ID from the organization settings page.
957
+ email (str): The email address associated with the invite.
958
+
959
+ Raises:
960
+ GRPCError: If no pending invite is associated with the provided email address.
961
+
962
+ Returns:
963
+ viam.proto.app.OrganizationInvite: The organization invite sent.
964
+
965
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#resendorganizationinvite>`_.
966
+ """
967
+ request = ResendOrganizationInviteRequest(organization_id=org_id, email=email)
968
+ response: ResendOrganizationInviteResponse = await self._app_client.ResendOrganizationInvite(request, metadata=self._metadata)
969
+ return response.invite
970
+
971
+ async def create_location(self, org_id: str, name: str, parent_location_id: Optional[str] = None) -> Location:
972
+ """Create and name a location under the currently authed-to organization and the specified parent location.
973
+
974
+ ::
975
+
976
+ my_new_location = await cloud.create_location(org_id="<YOUR-ORG-ID>", name="Robotville", parent_location_id="111ab12345")
977
+
978
+ Args:
979
+ org_id (str): The ID of the organization to create the location under.
980
+ You can obtain your organization ID from the organization settings page.
981
+ name (str): Name of the location.
982
+ parent_location_id (Optional[str]): Optional parent location to put the location under. Defaults to a root-level location if no
983
+ location ID is provided.
984
+
985
+ Raises:
986
+ GRPCError: If either an invalid name (for example, ""), or parent location ID (for example, a nonexistent ID) is passed.
987
+
988
+ Returns:
989
+ viam.proto.app.Location: The newly created location.
990
+
991
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createlocation>`_.
992
+ """
993
+ request = CreateLocationRequest(organization_id=org_id, name=name, parent_location_id=parent_location_id)
994
+ response: CreateLocationResponse = await self._app_client.CreateLocation(request, metadata=self._metadata)
995
+ return response.location
996
+
997
+ async def get_location(self, location_id: Optional[str] = None) -> Location:
998
+ """Get a location.
999
+
1000
+ ::
1001
+
1002
+ location = await cloud.get_location(location_id="123ab12345")
1003
+
1004
+ Args:
1005
+ location_id (Optional[str]): ID of the location to get. Defaults to the location ID provided at `AppClient` instantiation.
1006
+
1007
+ Raises:
1008
+ GRPCError: If an invalid location ID is passed or if one isn't passed and there was no location ID provided at `AppClient`
1009
+ instantiation.
1010
+
1011
+ Returns:
1012
+ viam.proto.app.Location: The location.
1013
+
1014
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getlocation>`_.
1015
+ """
1016
+ request = GetLocationRequest(location_id=location_id if location_id else "")
1017
+ response: GetLocationResponse = await self._app_client.GetLocation(request, metadata=self._metadata)
1018
+ return response.location
1019
+
1020
+ async def update_location(self, location_id: str, name: Optional[str] = None, parent_location_id: Optional[str] = None) -> Location:
1021
+ """Change the name of a location and/or assign it a new parent location.
1022
+
1023
+ ::
1024
+
1025
+ # The following line takes the location with ID "abc12abcde" and moves it to be a
1026
+ # sub-location of the location with ID "xyz34xxxxx"
1027
+ my_updated_location = await cloud.update_location(
1028
+ location_id="abc12abcde",
1029
+ name="",
1030
+ parent_location_id="xyz34xxxxx",
1031
+ )
1032
+
1033
+ # The following line changes the name of the location without changing its parent location
1034
+ my_updated_location = await cloud.update_location(
1035
+ location_id="abc12abcde",
1036
+ name="Land Before Robots"
1037
+ )
1038
+
1039
+ # The following line moves the location back up to be a top level location without changing its name
1040
+ my_updated_location = await cloud.update_location(
1041
+ location_id="abc12abcde",
1042
+ name="",
1043
+ parent_location_id=""
1044
+ )
1045
+
1046
+ Args:
1047
+ location_id (str): ID of the location to update. Must be specified.
1048
+ name (Optional[str]): Optional new name to be updated on the location. Defaults to the empty string "" (that is, the name
1049
+ doesn't change).
1050
+ parent_location_id(Optional[str]): Optional ID of new parent location to move the location under. Defaults to the empty string
1051
+ "" (that is, no new parent location is assigned).
1052
+
1053
+ Raises:
1054
+ GRPCError: If either an invalid location ID, name, or parent location ID is passed.
1055
+
1056
+ Returns:
1057
+ viam.proto.app.Location: The newly updated location.
1058
+
1059
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updatelocation>`_.
1060
+ """
1061
+ request = UpdateLocationRequest(location_id=location_id, name=name, parent_location_id=parent_location_id)
1062
+ response: UpdateLocationResponse = await self._app_client.UpdateLocation(request, metadata=self._metadata)
1063
+ return response.location
1064
+
1065
+ async def delete_location(self, location_id: str) -> None:
1066
+ """Delete a location.
1067
+
1068
+ ::
1069
+
1070
+ await cloud.delete_location(location_id="abc12abcde")
1071
+
1072
+ Args:
1073
+ location_id (str): ID of the location to delete. Must be specified.
1074
+
1075
+ Raises:
1076
+ GRPCError: If an invalid location ID is passed.
1077
+
1078
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deletelocation>`_.
1079
+ """
1080
+ request = DeleteLocationRequest(location_id=location_id)
1081
+ await self._app_client.DeleteLocation(request, metadata=self._metadata)
1082
+
1083
+ async def list_locations(self, org_id: str) -> List[Location]:
1084
+ """Get a list of all locations under the currently authed-to organization.
1085
+
1086
+ ::
1087
+
1088
+ locations = await cloud.list_locations("<YOUR-ORG-ID>")
1089
+
1090
+ Args:
1091
+ org_id (str): The ID of the org to list locations for.
1092
+ You can obtain your organization ID from the organization settings page.
1093
+
1094
+ Returns:
1095
+ List[viam.proto.app.Location]: The list of locations.
1096
+
1097
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listlocations>`_.
1098
+ """
1099
+ request = ListLocationsRequest(organization_id=org_id)
1100
+ response: ListLocationsResponse = await self._app_client.ListLocations(request, metadata=self._metadata)
1101
+ return list(response.locations)
1102
+
1103
+ async def share_location(self, organization_id: str, location_id: str) -> None:
1104
+ """Share a location with an organization.
1105
+
1106
+ ::
1107
+
1108
+ await cloud.share_location("<YOUR-ORG-ID>", "<YOUR-LOCATION-ID>")
1109
+
1110
+ Args:
1111
+ organization_id (str): The ID of the organization.
1112
+ location_id (str): The ID of the location.
1113
+
1114
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#sharelocation>`_.
1115
+ """
1116
+ request = ShareLocationRequest(location_id=location_id, organization_id=organization_id)
1117
+ await self._app_client.ShareLocation(request, metadata=self._metadata)
1118
+
1119
+ async def unshare_location(self, organization_id: str, location_id: str) -> None:
1120
+ """Stop sharing a location with an organization.
1121
+
1122
+ ::
1123
+
1124
+ await cloud.unshare_location("<YOUR-ORG-ID>", "<YOUR-LOCATION-ID>")
1125
+
1126
+ Args:
1127
+ organization_id (str): The ID of the organization.
1128
+ location_id (str): The ID of the location.
1129
+
1130
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#unsharelocation>`_.
1131
+ """
1132
+ request = UnshareLocationRequest(location_id=location_id, organization_id=organization_id)
1133
+ await self._app_client.UnshareLocation(request, metadata=self._metadata)
1134
+
1135
+ async def location_auth(self, location_id: Optional[str] = None) -> LocationAuth:
1136
+ """Get a location's `LocationAuth` (location secret(s)).
1137
+
1138
+ ::
1139
+
1140
+ loc_auth = await cloud.location_auth(location_id="123xy12345")
1141
+
1142
+ Args:
1143
+ location_id (str): ID of the location to retrieve `LocationAuth` from. Defaults to the location ID provided at `AppClient`
1144
+ instantiation.
1145
+
1146
+ Raises:
1147
+ GRPCError: If an invalid location ID is passed or if one isn't passed and there was no location ID provided at `AppClient`
1148
+ instantiation.
1149
+
1150
+ Returns:
1151
+ viam.proto.app.LocationAuth: The `LocationAuth` containing location secrets.
1152
+
1153
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#locationauth>`_.
1154
+ """
1155
+ request = LocationAuthRequest(location_id=location_id if location_id else "")
1156
+ response: LocationAuthResponse = await self._app_client.LocationAuth(request, metadata=self._metadata)
1157
+ return response.auth
1158
+
1159
+ async def create_location_secret(self, location_id: Optional[str] = None) -> LocationAuth:
1160
+ """Create a new location secret.
1161
+
1162
+ ::
1163
+
1164
+ new_loc_auth = await cloud.create_location_secret(location_id="123xy12345")
1165
+
1166
+ Args:
1167
+ location_id (Optional[str]): ID of the location to generate a new secret for. Defaults to the location ID provided at
1168
+ `AppClient` instantiation.
1169
+
1170
+ Raises:
1171
+ GRPCError: If an invalid location ID is passed or one isn't passed and there was no location ID provided at `AppClient`
1172
+ instantiation.
1173
+
1174
+ Returns:
1175
+ viam.proto.app.LocationAuth: The specified location's `LocationAuth` containing the newly created secret.
1176
+
1177
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createlocationsecret>`_.
1178
+ """
1179
+ request = CreateLocationSecretRequest(location_id=location_id if location_id else "")
1180
+ response: CreateLocationSecretResponse = await self._app_client.CreateLocationSecret(request, metadata=self._metadata)
1181
+ return response.auth
1182
+
1183
+ async def delete_location_secret(self, secret_id: str, location_id: Optional[str] = None) -> None:
1184
+ """Delete a location secret.
1185
+
1186
+ ::
1187
+
1188
+ await cloud.delete_location_secret(
1189
+ secret_id="abcd123-456-7890ab-cxyz98-989898xyzxyz",
1190
+ location_id="123xy12345"
1191
+ )
1192
+
1193
+ Args:
1194
+ location_id (str): ID of the location to delete secret from. Defaults to the location ID provided at `AppClient` instantiation.
1195
+ secret_id (str): ID of the secret to delete.
1196
+
1197
+ Raises:
1198
+ GRPCError: If either an invalid location ID or secret ID is passed or a location ID isn't passed and there was no location
1199
+ ID provided at `AppClient` instantiation.
1200
+
1201
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deletelocationsecret>`_.
1202
+ """
1203
+ request = DeleteLocationSecretRequest(location_id=location_id if location_id else "", secret_id=secret_id)
1204
+ await self._app_client.DeleteLocationSecret(request, metadata=self._metadata)
1205
+
1206
+ async def get_robot(self, robot_id: str) -> Robot:
1207
+ """Get a machine.
1208
+
1209
+ ::
1210
+
1211
+ machine = await cloud.get_robot(robot_id="1a123456-x1yz-0ab0-a12xyzabc")
1212
+
1213
+ Args:
1214
+ robot_id (str): ID of the machine to get. You can copy this value from the URL of the machine's page.
1215
+
1216
+ Raises:
1217
+ GRPCError: If an invalid machine ID is passed.
1218
+
1219
+ Returns:
1220
+ viam.proto.app.Robot: The machine.
1221
+
1222
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getrobot>`_.
1223
+ """
1224
+ request = GetRobotRequest(id=robot_id)
1225
+ response: GetRobotResponse = await self._app_client.GetRobot(request, metadata=self._metadata)
1226
+ return response.robot
1227
+
1228
+ async def get_rover_rental_robots(self, org_id: str) -> List[RoverRentalRobot]:
1229
+ """Returns a list of rover rental robots within an org.
1230
+
1231
+ ::
1232
+
1233
+ rental_robots = await cloud.get_rover_rental_robots()
1234
+
1235
+ Args:
1236
+ org_id (str): The ID of the organization to list rover rental robots for.
1237
+ You can obtain your organization ID from the organization settings page.
1238
+
1239
+ Returns:
1240
+ List[viam.proto.app.RoverRentalRobot]: The list of rover rental robots.
1241
+
1242
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/>`_.
1243
+ """
1244
+ request = GetRoverRentalRobotsRequest(org_id=org_id)
1245
+ response: GetRoverRentalRobotsResponse = await self._app_client.GetRoverRentalRobots(request, metadata=self._metadata)
1246
+ return list(response.robots)
1247
+
1248
+ async def get_robot_parts(self, robot_id: str) -> List[RobotPart]:
1249
+ """Get a list of all the parts under a specific machine.
1250
+
1251
+ ::
1252
+
1253
+ list_of_parts = await cloud.get_robot_parts(
1254
+ robot_id="1a123456-x1yz-0ab0-a12xyzabc"
1255
+ )
1256
+
1257
+ Args:
1258
+ robot_id (str): ID of the machine to get parts from.
1259
+
1260
+ Raises:
1261
+ GRPCError: If an invalid machine ID is passed.
1262
+
1263
+ Returns:
1264
+ List[viam.app.app_client.RobotPart]: The list of machine parts.
1265
+
1266
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getrobotparts>`_.
1267
+ """
1268
+ request = GetRobotPartsRequest(robot_id=robot_id)
1269
+ response: GetRobotPartsResponse = await self._app_client.GetRobotParts(request, metadata=self._metadata)
1270
+ return [RobotPart.from_proto(robot_part=part) for part in response.parts]
1271
+
1272
+ async def get_robot_part(self, robot_part_id: str, dest: Optional[str] = None, indent: int = 4) -> RobotPart:
1273
+ """Get a machine part including its part config, part address, and other information.
1274
+
1275
+ ::
1276
+
1277
+ my_robot_part = await cloud.get_robot_part(
1278
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22"
1279
+ )
1280
+ # Get the part's config
1281
+ machine_part_config = my_robot_part.robot_config
1282
+ # Get the part's address
1283
+ address = my_robot_part.fqdn
1284
+ # Check if machine is live (last access time less than 10 sec ago)
1285
+ if (time.time() - my_robot_part.last_access.timestamp()) <= 10000:
1286
+ print("Machine is live.")
1287
+
1288
+ Args:
1289
+ robot_part_id (str): ID of the machine part to get. You can retrieve this value by navigating to the machine's page,
1290
+ clicking on the part status dropdown, and clicking the copy icon next to Part ID.
1291
+ dest (Optional[str]): Optional filepath to write the machine part's config file in JSON format to.
1292
+ indent (int): Size (in number of spaces) of indent when writing config to `dest`. Defaults to 4.
1293
+
1294
+ Raises:
1295
+ GRPCError: If an invalid machine part ID is passed.
1296
+
1297
+ Returns:
1298
+ viam.app.app_client.RobotPart: The machine part.
1299
+
1300
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getrobotpart>`_.
1301
+ """
1302
+ request = GetRobotPartRequest(id=robot_part_id)
1303
+ response: GetRobotPartResponse = await self._app_client.GetRobotPart(request, metadata=self._metadata)
1304
+
1305
+ if dest:
1306
+ try:
1307
+ file = open(dest, "w")
1308
+ file.write(f"{json.dumps(json.loads(response.config_json), indent=indent)}")
1309
+ file.flush()
1310
+ except Exception as e:
1311
+ LOGGER.error(f"Failed to write config JSON to file {dest}", exc_info=e)
1312
+
1313
+ return RobotPart.from_proto(robot_part=response.part)
1314
+
1315
+ async def get_robot_part_logs(
1316
+ self,
1317
+ robot_part_id: str,
1318
+ filter: Optional[str] = None,
1319
+ dest: Optional[str] = None,
1320
+ log_levels: List[str] = [],
1321
+ num_log_entries: int = 100,
1322
+ ) -> List[LogEntry]:
1323
+ """Get the logs associated with a robot part.
1324
+
1325
+ ::
1326
+
1327
+ part_logs = await cloud.get_robot_part_logs(
1328
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22",
1329
+ num_log_entries=20
1330
+ )
1331
+
1332
+ Args:
1333
+ robot_part_id (str): ID of the machine part to get logs from.
1334
+ filter (Optional[str]): Only include logs with messages that contain the string `filter`. Defaults to empty string "" (that is,
1335
+ no filter).
1336
+ dest (Optional[str]): Optional filepath to write the log entries to.
1337
+ log_levels (List[str]): List of log levels for which entries should be returned. Defaults to empty list, which returns all logs.
1338
+ num_log_entries (int): Number of log entries to return. Passing 0 returns all logs. Defaults to 100. All logs or the first
1339
+ `num_log_entries` logs will be returned, whichever comes first.
1340
+
1341
+ Raises:
1342
+ GRPCError: If an invalid robot part ID is passed.
1343
+
1344
+ Returns:
1345
+ List[viam.app.app_client.LogEntry]: The list of log entries.
1346
+
1347
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getrobotpartlogs>`_.
1348
+ """
1349
+ if num_log_entries < 0:
1350
+ raise ValueError("'num_log_entries must be at least 0.")
1351
+ logs_left = num_log_entries
1352
+ page_token = ""
1353
+ logs = []
1354
+
1355
+ while True:
1356
+ new_logs, next_page_token = await self._get_robot_part_logs(
1357
+ robot_part_id=robot_part_id, filter=filter if filter else "", page_token=page_token, log_levels=log_levels
1358
+ )
1359
+ if num_log_entries != 0 and len(new_logs) > logs_left:
1360
+ logs += new_logs[0:logs_left]
1361
+ break
1362
+ logs += new_logs
1363
+ logs_left -= len(new_logs)
1364
+ if not next_page_token or next_page_token == "" or logs_left == 0:
1365
+ break
1366
+ page_token = next_page_token
1367
+
1368
+ if dest:
1369
+ try:
1370
+ file = open(dest, "w")
1371
+ for log in logs:
1372
+ time = log.time
1373
+ level = log.level.upper()
1374
+ logger_name = log.logger_name.split(".")[0]
1375
+ file_name = log.caller["File"] + ":" + str(int(log.caller["Line"]))
1376
+ message = log.message
1377
+ file.write(f"{time}\t{level}\t{logger_name}\t{file_name:<64}{message}\n")
1378
+ file.flush()
1379
+ except Exception as e:
1380
+ LOGGER.error(f"Failed to write robot part from robot part with ID [{robot_part_id}]logs to file {dest}", exc_info=e)
1381
+
1382
+ return logs
1383
+
1384
+ async def _get_robot_part_logs(
1385
+ self, robot_part_id: str, filter: str, page_token: str, log_levels: List[str]
1386
+ ) -> Tuple[List[LogEntry], str]:
1387
+ request = GetRobotPartLogsRequest(id=robot_part_id, filter=filter, page_token=page_token, levels=log_levels)
1388
+ response: GetRobotPartLogsResponse = await self._app_client.GetRobotPartLogs(request, metadata=self._metadata)
1389
+ return [LogEntry.from_proto(log) for log in response.logs], response.next_page_token
1390
+
1391
+ async def tail_robot_part_logs(
1392
+ self, robot_part_id: str, errors_only: bool = True, filter: Optional[str] = None
1393
+ ) -> _LogsStream[List[LogEntry]]:
1394
+ """Get an asynchronous iterator that receives live machine part logs.
1395
+
1396
+ ::
1397
+
1398
+ logs_stream = await cloud.tail_robot_part_logs(
1399
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22"
1400
+ )
1401
+
1402
+ Args:
1403
+ robot_part_id (str): ID of the machine part to retrieve logs from.
1404
+ errors_only (bool): Boolean specifying whether or not to only include error logs. Defaults to True.
1405
+ filter (Optional[str]): Only include logs with messages that contain the string `filter`. Defaults to empty string "" (that is,
1406
+ no filter).
1407
+
1408
+ Returns:
1409
+ _LogsStream[List[LogEntry]]: The asynchronous iterator receiving live machine part logs.
1410
+ """
1411
+
1412
+ async def read() -> AsyncIterator[List[LogEntry]]:
1413
+ async with self._app_client.TailRobotPartLogs.open(metadata=self._metadata) as stream:
1414
+ await stream.send_message(
1415
+ TailRobotPartLogsRequest(id=robot_part_id, errors_only=errors_only, filter=filter if filter else "")
1416
+ )
1417
+
1418
+ while True:
1419
+ response: Optional[TailRobotPartLogsResponse] = await stream.recv_message()
1420
+ if response is None or len(response.logs) == 0:
1421
+ break
1422
+ logs = [LogEntry.from_proto(log) for log in response.logs]
1423
+ yield logs
1424
+
1425
+ return _LogsStreamWithIterator(read())
1426
+
1427
+ async def get_robot_part_history(self, robot_part_id: str) -> List[RobotPartHistoryEntry]:
1428
+ """Get a list containing the history of a machine part.
1429
+
1430
+ ::
1431
+
1432
+ part_history = await cloud.get_robot_part_history(
1433
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22"
1434
+ )
1435
+
1436
+ Args:
1437
+ robot_part_id (str): ID of the machine part to retrieve history from.
1438
+
1439
+ Raises:
1440
+ GRPCError: If an invalid machine part ID is provided.
1441
+
1442
+ Returns:
1443
+ List[viam.app.app_client.RobotPartHistoryEntry]: The list of the machine part's history.
1444
+
1445
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getrobotapikeys>`_.
1446
+ """
1447
+ request = GetRobotPartHistoryRequest(id=robot_part_id)
1448
+ response: GetRobotPartHistoryResponse = await self._app_client.GetRobotPartHistory(request, metadata=self._metadata)
1449
+ return [RobotPartHistoryEntry.from_proto(part_history) for part_history in response.history]
1450
+
1451
+ async def update_robot_part(
1452
+ self, robot_part_id: str, name: str, robot_config: Optional[Mapping[str, Any]] = None, last_known_update: Optional[datetime] = None
1453
+ ) -> RobotPart:
1454
+ """Change the name and assign an optional new configuration to a machine part.
1455
+
1456
+ ::
1457
+
1458
+ my_machine_part = await cloud.update_robot_part(
1459
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22"
1460
+ )
1461
+
1462
+ Args:
1463
+ robot_part_id (str): ID of the robot part to update.
1464
+ name (str): New name to be updated on the robot part.
1465
+ robot_config (Mapping[str, Any]): Optional new config represented as a dictionary to be updated on the machine part. The machine
1466
+ part's config will remain as is (no change) if one isn't passed.
1467
+ last_known_update (datetime): Optional time of the last known update to this part's config. If provided, this will result in a
1468
+ GRPCError if the upstream config has changed since this time, indicating that the local config is out of date. Omitting this
1469
+ parameter will result in an overwrite of the upstream config.
1470
+ Raises:
1471
+ GRPCError: If either an invalid machine part ID, name, or config is passed, or if the upstream config has changed since
1472
+ last_known_update.
1473
+ Returns:
1474
+ viam.app.app_client.RobotPart: The newly updated robot part.
1475
+
1476
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updaterobotpart>`_.
1477
+ """
1478
+ request = UpdateRobotPartRequest(
1479
+ id=robot_part_id,
1480
+ name=name,
1481
+ robot_config=dict_to_struct(robot_config) if robot_config else None,
1482
+ last_known_update=datetime_to_timestamp(last_known_update),
1483
+ )
1484
+ response: UpdateRobotPartResponse = await self._app_client.UpdateRobotPart(request, metadata=self._metadata)
1485
+ return RobotPart.from_proto(robot_part=response.part)
1486
+
1487
+ async def new_robot_part(self, robot_id: str, part_name: str) -> str:
1488
+ """Create a new machine part.
1489
+
1490
+ ::
1491
+
1492
+ new_part_id = await cloud.new_robot_part(
1493
+ robot_id="1a123456-x1yz-0ab0-a12xyzabc", part_name="myNewSubPart"
1494
+ )
1495
+
1496
+ Args:
1497
+ robot_id (str): ID of the machine to create a new part for.
1498
+ part_name (str): Name of the new part.
1499
+
1500
+ Raises:
1501
+ GRPCError: If either an invalid machine ID or name is passed.
1502
+
1503
+ Returns:
1504
+ str: The new machine part's ID.
1505
+
1506
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#newrobotpart>`_.
1507
+ """
1508
+ request = NewRobotPartRequest(robot_id=robot_id, part_name=part_name)
1509
+ response: NewRobotPartResponse = await self._app_client.NewRobotPart(request, metadata=self._metadata)
1510
+ return response.part_id
1511
+
1512
+ async def delete_robot_part(self, robot_part_id: str) -> None:
1513
+ """Delete the specified machine part.
1514
+
1515
+ ::
1516
+
1517
+ await cloud.delete_robot_part(
1518
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22"
1519
+ )
1520
+
1521
+ Args:
1522
+ robot_part_id (str): ID of the machine part to delete. Must be specified.
1523
+
1524
+ Raises:
1525
+ GRPCError: If an invalid machine part ID is passed.
1526
+
1527
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deleterobotpart>`_.
1528
+ """
1529
+ request = DeleteRobotPartRequest(part_id=robot_part_id)
1530
+ await self._app_client.DeleteRobotPart(request, metadata=self._metadata)
1531
+
1532
+ async def get_robot_api_keys(self, robot_id: str) -> List[APIKeyWithAuthorizations]:
1533
+ """Gets the API Keys for the machine.
1534
+
1535
+ ::
1536
+
1537
+ api_keys = await cloud.get_robot_api_keys(robot_id="robot-id")
1538
+
1539
+ Args:
1540
+ robot_id (str): The ID of the machine.
1541
+
1542
+ Returns:
1543
+ List[APIKeyWithAuthorizations]: The list of API keys.
1544
+
1545
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getrobotapikeys>`_.
1546
+ """
1547
+ request = GetRobotAPIKeysRequest(robot_id=robot_id)
1548
+ response: GetRobotAPIKeysResponse = await self._app_client.GetRobotAPIKeys(request, metadata=self._metadata)
1549
+ return list(response.api_keys)
1550
+
1551
+ async def mark_part_as_main(self, robot_part_id: str) -> None:
1552
+ """Mark a machine part as the main part of a machine.
1553
+
1554
+ ::
1555
+
1556
+ await cloud.mark_part_as_main(
1557
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22")
1558
+
1559
+ Args:
1560
+ robot_part_id (str): ID of the machine part to mark as main.
1561
+
1562
+ Raises:
1563
+ GRPCError: If an invalid machine part ID is passed.
1564
+
1565
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#markpartasmain>`_.
1566
+ """
1567
+ request = MarkPartAsMainRequest(part_id=robot_part_id)
1568
+ await self._app_client.MarkPartAsMain(request, metadata=self._metadata)
1569
+
1570
+ async def mark_part_for_restart(self, robot_part_id: str) -> None:
1571
+ """Mark the specified machine part for restart.
1572
+
1573
+ ::
1574
+
1575
+ await cloud.mark_part_for_restart(
1576
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22")
1577
+
1578
+ Args:
1579
+ robot_part_id (str): ID of the machine part to mark for restart.
1580
+
1581
+ Raises:
1582
+ GRPCError: If an invalid machine part ID is passed.
1583
+
1584
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#markpartforrestart>`_.
1585
+ """
1586
+ request = MarkPartForRestartRequest(part_id=robot_part_id)
1587
+ await self._app_client.MarkPartForRestart(request, metadata=self._metadata)
1588
+
1589
+ async def create_robot_part_secret(self, robot_part_id: str) -> RobotPart:
1590
+ """Create a machine part secret.
1591
+
1592
+ ::
1593
+
1594
+ part_with_new_secret = await cloud.create_robot_part_secret(
1595
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22")
1596
+
1597
+ Args:
1598
+ robot_part_id (str): ID of the machine part to create a secret for.
1599
+
1600
+ Raises:
1601
+ GRPCError: If an invalid machine part ID is passed.
1602
+
1603
+ Returns:
1604
+ viam.app.app_client.RobotPart: The machine part the new secret was generated for.
1605
+
1606
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createrobotpartsecret>`_.
1607
+ """
1608
+ request = CreateRobotPartSecretRequest(part_id=robot_part_id)
1609
+ response: CreateRobotPartSecretResponse = await self._app_client.CreateRobotPartSecret(request, metadata=self._metadata)
1610
+ return RobotPart.from_proto(response.part)
1611
+
1612
+ async def delete_robot_part_secret(self, robot_part_id: str, secret_id: str) -> None:
1613
+ """Delete a machine part secret.
1614
+
1615
+ ::
1616
+
1617
+ await cloud.delete_robot_part_secret(
1618
+ robot_part_id="abc12345-1a23-1234-ab12-a22a22a2aa22",
1619
+ secret_id="123xyz12-abcd-4321-12ab-12xy1xyz12xy")
1620
+
1621
+ Args:
1622
+ robot_part_id (str): ID of the machine part to delete the secret from.
1623
+ secret_id (str): ID of the secret to delete.
1624
+
1625
+ Raises:
1626
+ GRPCError: If an invalid machine part ID or secret ID is passed.
1627
+
1628
+ For more information, see `Fleet Management API <hhttps://docs.viam.com/dev/reference/apis/fleet/#deleterobotpartsecret>`_.
1629
+ """
1630
+ request = DeleteRobotPartSecretRequest(part_id=robot_part_id, secret_id=secret_id)
1631
+ await self._app_client.DeleteRobotPartSecret(request, metadata=self._metadata)
1632
+
1633
+ async def list_robots(self, location_id: Optional[str] = None) -> List[Robot]:
1634
+ """Get a list of all machines under the specified location.
1635
+
1636
+ ::
1637
+
1638
+ list_of_machines = await cloud.list_robots(location_id="123ab12345")
1639
+
1640
+ Args:
1641
+ location_id (Optional[str]): ID of the location to retrieve the machines from. Defaults to the location ID provided at
1642
+ `AppClient` instantiation.
1643
+
1644
+ Raises:
1645
+ GRPCError: If an invalid location ID is passed or one isn't passed and there was no location ID provided at `AppClient`
1646
+ instantiation.
1647
+
1648
+ Returns:
1649
+ List[viam.proto.app.Robot]: The list of robots.
1650
+
1651
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listrobots>`_.
1652
+ """
1653
+ request = ListRobotsRequest(location_id=location_id if location_id else "")
1654
+ response: ListRobotsResponse = await self._app_client.ListRobots(request, metadata=self._metadata)
1655
+ return list(response.robots)
1656
+
1657
+ async def new_robot(self, name: str, location_id: Optional[str] = None) -> str:
1658
+ """Create a new machine.
1659
+
1660
+ ::
1661
+
1662
+ new_machine_id = await cloud.new_robot(name="beepboop", location_id="my-location-id")
1663
+
1664
+ Args:
1665
+ name (str): Name of the new machine.
1666
+ location_id (Optional[str]): ID of the location under which to create the machine. Defaults to the current authorized location.
1667
+
1668
+ Raises:
1669
+ GRPCError: If an invalid location ID is passed or one isn't passed and there was no location ID provided at `AppClient`
1670
+ instantiation.
1671
+
1672
+ Returns:
1673
+ str: The new robot's ID.
1674
+
1675
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#newrobot>`_.
1676
+ """
1677
+ request = NewRobotRequest(location=location_id if location_id else "", name=name)
1678
+ response: NewRobotResponse = await self._app_client.NewRobot(request, metadata=self._metadata)
1679
+ return response.id
1680
+
1681
+ async def update_robot(self, robot_id: str, name: str, location_id: Optional[str] = None) -> Robot:
1682
+ """Change the name of an existing machine.
1683
+
1684
+ ::
1685
+
1686
+ updated_robot = await cloud.update_robot(
1687
+ robot_id="1a123456-x1yz-0ab0-a12xyzabc",
1688
+ name="Orange-Robot",
1689
+ location_id="23ab12345"
1690
+ )
1691
+
1692
+ Args:
1693
+ robot_id (str): ID of the machine to update.
1694
+ name (str): New name to be updated on the machine.
1695
+ location_id (Optional[str]): ID of the location under which the machine exists. Defaults to the location ID provided at
1696
+ `AppClient` instantiation
1697
+
1698
+ Raises:
1699
+ GRPCError: If either an invalid machine ID, name, or location ID is passed or a location ID isn't passed and there was no
1700
+ location ID provided at `AppClient` instantiation.
1701
+
1702
+ Returns:
1703
+ viam.proto.app.Robot: The newly updated machine.
1704
+
1705
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updaterobot>`_.
1706
+ """
1707
+ request = UpdateRobotRequest(id=robot_id, name=name, location=location_id if location_id else "")
1708
+ response: UpdateRobotResponse = await self._app_client.UpdateRobot(request, metadata=self._metadata)
1709
+ return response.robot
1710
+
1711
+ async def delete_robot(self, robot_id: str) -> None:
1712
+ """Delete the specified machine.
1713
+
1714
+ ::
1715
+
1716
+ await cloud.delete_robot(robot_id="1a123456-x1yz-0ab0-a12xyzabc")
1717
+
1718
+ Args:
1719
+ robot_id (str): ID of the machine to delete.
1720
+
1721
+ Raises:
1722
+ GRPCError: If an invalid machine ID is passed.
1723
+
1724
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deleterobot>`_.
1725
+ """
1726
+ request = DeleteRobotRequest(id=robot_id)
1727
+ await self._app_client.DeleteRobot(request, metadata=self._metadata)
1728
+
1729
+ async def list_fragments(
1730
+ self, org_id: str, show_public: bool = True, visibilities: Optional[List[Fragment.Visibility]] = None
1731
+ ) -> List[Fragment]:
1732
+ """Get a list of fragments under the currently authed-to organization.
1733
+
1734
+ ::
1735
+
1736
+ fragments_list = await cloud.list_fragments(org_id="org-id", visibilities=[])
1737
+
1738
+ Args:
1739
+ org_id (str): The ID of the organization to list fragments for.
1740
+ You can obtain your organization ID from the organization settings page.
1741
+ show_public (bool): Optional boolean specifying whether or not to only show public fragments. If True, only public fragments
1742
+ will return. If False, only private fragments will return. Defaults to True.
1743
+
1744
+ .. deprecated:: 0.25.0
1745
+ Use ``visibilities`` instead.
1746
+ visibilities (Optional[List[Fragment.Visibility]]): List of FragmentVisibilities specifying which types of fragments to include
1747
+ in the results. If empty, by default only public fragments will be returned.
1748
+
1749
+ Returns:
1750
+ List[viam.app.app_client.Fragment]: The list of fragments.
1751
+
1752
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listfragments>`_.
1753
+ """
1754
+ request = ListFragmentsRequest(
1755
+ organization_id=org_id,
1756
+ fragment_visibility=map(Fragment.Visibility.to_proto, visibilities if visibilities else []),
1757
+ show_public=show_public,
1758
+ )
1759
+ response: ListFragmentsResponse = await self._app_client.ListFragments(request, metadata=self._metadata)
1760
+ return [Fragment.from_proto(fragment=fragment) for fragment in response.fragments]
1761
+
1762
+ async def get_fragment(self, fragment_id: str, version: Optional[str] = None) -> Fragment:
1763
+ """Get a fragment.
1764
+
1765
+ ::
1766
+
1767
+ # Get a fragment and print its name and when it was created.
1768
+ the_fragment = await cloud.get_fragment(
1769
+ fragment_id="12a12ab1-1234-5678-abcd-abcd01234567")
1770
+ print("Name: ", the_fragment.name, "\\nCreated on: ", the_fragment.created_on)
1771
+
1772
+ Args:
1773
+ fragment_id (str): ID of the fragment to get.
1774
+ version (str): Optional specification of the fragment version to get (revision or tag).
1775
+
1776
+ Raises:
1777
+ GRPCError: If an invalid fragment ID is passed.
1778
+
1779
+ Returns:
1780
+ viam.app.app_client.Fragment: The fragment.
1781
+
1782
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getfragment>`_.
1783
+ """
1784
+ request = GetFragmentRequest(id=fragment_id, version=version)
1785
+ response: GetFragmentResponse = await self._app_client.GetFragment(request, metadata=self._metadata)
1786
+ return Fragment.from_proto(fragment=response.fragment)
1787
+
1788
+ async def create_fragment(self, org_id: str, name: str, config: Optional[Mapping[str, Any]] = None) -> Fragment:
1789
+ """Create a new private fragment.
1790
+
1791
+ ::
1792
+
1793
+ new_fragment = await cloud.create_fragment(org_id="org-id", name="cool_smart_machine_to_configure_several_of")
1794
+
1795
+ Args:
1796
+ org_id (str): The ID of the organization to create the fragment within.
1797
+ You can obtain your organization ID from the organization settings page.
1798
+ name (str): Name of the fragment.
1799
+ config (Optional[Mapping[str, Any]]): Optional Dictionary representation of new config to assign to specified fragment. Can be
1800
+ assigned by updating the fragment.
1801
+
1802
+ Raises:
1803
+ GRPCError: If an invalid name is passed.
1804
+
1805
+ Returns:
1806
+ viam.app.app_client.Fragment: The newly created fragment.
1807
+
1808
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createfragment>`_.
1809
+ """
1810
+ request = CreateFragmentRequest(name=name, config=dict_to_struct(config) if config else None, organization_id=org_id)
1811
+ response: CreateFragmentResponse = await self._app_client.CreateFragment(request, metadata=self._metadata)
1812
+ return Fragment.from_proto(response.fragment)
1813
+
1814
+ async def update_fragment(
1815
+ self,
1816
+ fragment_id: str,
1817
+ name: str,
1818
+ config: Optional[Mapping[str, Any]] = None,
1819
+ public: Optional[bool] = None,
1820
+ visibility: Optional[Fragment.Visibility] = None,
1821
+ last_known_update: Optional[datetime] = None,
1822
+ ) -> Fragment:
1823
+ """Update a fragment name AND its config and/or visibility.
1824
+
1825
+ ::
1826
+
1827
+ updated_fragment = await cloud.update_fragment(
1828
+ fragment_id="12a12ab1-1234-5678-abcd-abcd01234567",
1829
+ name="better_name")
1830
+
1831
+ Args:
1832
+ fragment_id (str): ID of the fragment to update.
1833
+ name (str): New name to associate with the fragment.
1834
+ config (Optional[Mapping[str, Any]]): Optional Dictionary representation of new config to assign to specified fragment. Not
1835
+ passing this parameter will leave the fragment's config unchanged.
1836
+ public (bool): Boolean specifying whether the fragment is public. Not passing this parameter will leave the fragment's
1837
+ visibility unchanged. A fragment is private by default when created.
1838
+
1839
+ .. deprecated:: 0.25.0
1840
+ Use ``visibility`` instead.
1841
+ visibility (Optional[FragmentVisibility]): Optional FragmentVisibility list specifying who should be allowed
1842
+ to view the fragment. Not passing this parameter will leave the fragment's visibility unchanged.
1843
+ A fragment is private by default when created.
1844
+ last_known_update (datetime): Optional time of the last known update to this fragment's config. If provided, this will result in
1845
+ a GRPCError if the upstream config has changed since this time, indicating that the local config is out of date. Omitting
1846
+ this parameter will result in an overwrite of the upstream config.
1847
+ Raises:
1848
+ GRPCError: if an invalid ID, name, or config is passed, or if the upstream fragment config has changed since last_known_update.
1849
+
1850
+ Returns:
1851
+ viam.app.app_client.Fragment: The newly updated fragment.
1852
+
1853
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updatefragment>`_.
1854
+ """
1855
+ request = UpdateFragmentRequest(
1856
+ id=fragment_id,
1857
+ name=name,
1858
+ config=dict_to_struct(config) if config else None,
1859
+ public=public,
1860
+ visibility=visibility.to_proto() if visibility else None,
1861
+ last_known_update=datetime_to_timestamp(last_known_update),
1862
+ )
1863
+ response: UpdateFragmentResponse = await self._app_client.UpdateFragment(request, metadata=self._metadata)
1864
+ return Fragment.from_proto(response.fragment)
1865
+
1866
+ async def delete_fragment(self, fragment_id: str) -> None:
1867
+ """Delete a fragment.
1868
+
1869
+ ::
1870
+
1871
+ await cloud.delete_fragment(
1872
+ fragment_id="12a12ab1-1234-5678-abcd-abcd01234567")
1873
+
1874
+ Args:
1875
+ fragment_id (str): ID of the fragment to delete.
1876
+
1877
+ Raises:
1878
+ GRPCError: If an invalid fragment ID is passed.
1879
+
1880
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deletefragment>`_.
1881
+ """
1882
+ request = DeleteFragmentRequest(id=fragment_id)
1883
+ await self._app_client.DeleteFragment(request, metadata=self._metadata)
1884
+
1885
+ async def get_fragment_history(
1886
+ self, id: str, page_token: Optional[str] = "", page_limit: Optional[int] = 10
1887
+ ) -> List[FragmentHistoryEntry]:
1888
+ """Get fragment history.
1889
+
1890
+ ::
1891
+
1892
+ fragment_history = await cloud.get_fragment_history(
1893
+ id = "12a12ab1-1234-5678-abcd-abcd01234567",
1894
+ page_token = "pg-token",
1895
+ page_limit = 10
1896
+ )
1897
+
1898
+ Args:
1899
+ id (str): ID of the fragment to fetch history for.
1900
+ page_token (Optional[str]): the page token for the fragment history collection
1901
+ page_limit (Optional[int]): the number of fragment history documents to return in the result.
1902
+ The default page limit is 10.
1903
+
1904
+ Raises:
1905
+ GRPCError: if an invalid fragment id, page token or page limit is passed.
1906
+
1907
+ Returns:
1908
+ viam.app.app_client.FragmentHistoryResponse: A list of documents with the fragment history.
1909
+
1910
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getfragmenthistory>`_.
1911
+ """
1912
+
1913
+ request = GetFragmentHistoryRequest(id=id, page_token=page_token, page_limit=page_limit)
1914
+ response: GetFragmentHistoryResponse = await self._app_client.GetFragmentHistory(request, metadata=self._metadata)
1915
+ return [FragmentHistoryEntry.from_proto(fragment_history) for fragment_history in response.history]
1916
+
1917
+ async def add_role(
1918
+ self,
1919
+ org_id: str,
1920
+ identity_id: str,
1921
+ role: Union[Literal["owner"], Literal["operator"]],
1922
+ resource_type: Union[Literal["organization"], Literal["location"], Literal["robot"]],
1923
+ resource_id: str,
1924
+ ) -> None:
1925
+ """Add a role under the currently authed-to organization.
1926
+
1927
+ ::
1928
+
1929
+ await cloud.add_role(
1930
+ org_id="<YOUR-ORG-ID>",
1931
+ identity_id="abc01234-0123-4567-ab12-a11a00a2aa22",
1932
+ role="owner",
1933
+ resource_type="location",
1934
+ resource_id="111ab12345"
1935
+ )
1936
+
1937
+ Args:
1938
+ org_id (str): The ID of the organization to create the role in.
1939
+ You can obtain your organization ID from the organization settings page.
1940
+ identity_id (str): ID of the entity the role belongs to (for example, a user ID).
1941
+ role (Union[Literal["owner"], Literal["operator"]]): The role to add.
1942
+ resource_type (Union[Literal["organization"], Literal["location"], Literal["robot"]]): Type of the resource to add role to.
1943
+ Must match `resource_id`.
1944
+ resource_id (str): ID of the resource the role applies to (that is, either an organization, location, or robot ID).
1945
+
1946
+ Raises:
1947
+ GRPCError: If either an invalid identity ID, role ID, resource type, or resource ID is passed.
1948
+
1949
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#addrole>`_.
1950
+ """
1951
+ authorization = await self._create_authorization(
1952
+ organization_id=org_id,
1953
+ identity_id=identity_id,
1954
+ identity_type="",
1955
+ role=role,
1956
+ resource_type=resource_type,
1957
+ resource_id=resource_id,
1958
+ )
1959
+ request = AddRoleRequest(authorization=authorization)
1960
+ await self._app_client.AddRole(request, metadata=self._metadata)
1961
+
1962
+ async def remove_role(
1963
+ self,
1964
+ org_id: str,
1965
+ identity_id: str,
1966
+ role: Union[Literal["owner"], Literal["operator"]],
1967
+ resource_type: Union[Literal["organization"], Literal["location"], Literal["robot"]],
1968
+ resource_id: str,
1969
+ ) -> None:
1970
+ """Remove a role under the currently authed-to organization.
1971
+
1972
+ ::
1973
+
1974
+ await cloud.remove_role(
1975
+ org_id="<YOUR-ORG-ID>",
1976
+ identity_id="abc01234-0123-4567-ab12-a11a00a2aa22",
1977
+ role="owner",
1978
+ resource_type="location",
1979
+ resource_id="111ab12345"
1980
+ )
1981
+
1982
+ Args:
1983
+ org_id (str): The ID of the organization the role exists in.
1984
+ You can obtain your organization ID from the organization settings page.
1985
+ identity_id (str): ID of the entity the role belongs to (for example, a user ID).
1986
+ role (Union[Literal["owner"], Literal["operator"]]): The role to remove.
1987
+ resource_type (Union[Literal["organization"], Literal["location"], Literal["robot"]]): Type of the resource the role is being
1988
+ removed from. Must match `resource_id`.
1989
+ resource_id (str): ID of the resource the role applies to (that is, either an organization, location, or robot ID).
1990
+
1991
+ Raises:
1992
+ GRPCError: If either an invalid identity ID, role ID, resource type, or resource ID or is passed.
1993
+
1994
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#removerole>`_.
1995
+ """
1996
+ authorization = await self._create_authorization(
1997
+ organization_id=org_id,
1998
+ identity_id=identity_id,
1999
+ identity_type="",
2000
+ role=role,
2001
+ resource_type=resource_type,
2002
+ resource_id=resource_id,
2003
+ )
2004
+ request = RemoveRoleRequest(authorization=authorization)
2005
+ await self._app_client.RemoveRole(request, metadata=self._metadata)
2006
+
2007
+ async def change_role(
2008
+ self,
2009
+ organization_id: str,
2010
+ old_identity_id: str,
2011
+ old_role: Union[Literal["owner"], Literal["operator"]],
2012
+ old_resource_type: Union[Literal["organization"], Literal["location"], Literal["robot"]],
2013
+ old_resource_id: str,
2014
+ new_identity_id: str,
2015
+ new_role: Union[Literal["owner"], Literal["operator"]],
2016
+ new_resource_type: Union[Literal["organization"], Literal["location"], Literal["robot"]],
2017
+ new_resource_id: str,
2018
+ ) -> None:
2019
+ """Changes a role to a new role.
2020
+
2021
+ ::
2022
+
2023
+ await cloud.change_role(
2024
+ organization_id="<YOUR-ORG-ID>",
2025
+ old_identity_id="abc01234-0123-4567-ab12-a11a00a2aa22",
2026
+ old_role="operator",
2027
+ old_resource_type="location",
2028
+ old_resource_id="111ab12345",
2029
+ new_identity_id="abc01234-0123-4567-ab12-a11a00a2aa22",
2030
+ new_role="owner",
2031
+ new_resource_type="organization",
2032
+ new_resource_id="abc12345"
2033
+ )
2034
+
2035
+ Args:
2036
+ organization_id (str): ID of the organization
2037
+ old_identity_id (str): ID of the entity the role belongs to (for example, a user ID).
2038
+ old_role (Union[Literal["owner"], Literal["operator"]]): The role to be changed.
2039
+ old_resource_type (Union[Literal["organization"], Literal["location"], Literal["robot"]]): Type of the resource the role is
2040
+ added to. Must match `old_resource_id`.
2041
+ old_resource_id (str): ID of the resource the role applies to (that is, either an organization, location, or robot ID).
2042
+
2043
+ new_identity_id (str): New ID of the entity the role belongs to (for example, a user ID).
2044
+ new_role (Union[Literal["owner"], Literal["operator"]]): The new role.
2045
+ new_resource_type (Union[Literal["organization"], Literal["location"], Literal["robot"]]): Type of the resource to add role to.
2046
+ Must match `new_resource_id`.
2047
+ new_resource_id (str): New ID of the resource the role applies to (that is, either an organization, location, or robot ID).
2048
+
2049
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#changerole>`_.
2050
+ """
2051
+ old_authorization = await self._create_authorization(
2052
+ organization_id=organization_id,
2053
+ identity_id=old_identity_id,
2054
+ identity_type="",
2055
+ role=old_role,
2056
+ resource_type=old_resource_type,
2057
+ resource_id=old_resource_id,
2058
+ )
2059
+ new_authorization = await self._create_authorization(
2060
+ organization_id=organization_id,
2061
+ identity_id=new_identity_id,
2062
+ identity_type="",
2063
+ role=new_role,
2064
+ resource_type=new_resource_type,
2065
+ resource_id=new_resource_id,
2066
+ )
2067
+ request = ChangeRoleRequest(old_authorization=old_authorization, new_authorization=new_authorization)
2068
+ await self._app_client.ChangeRole(request, metadata=self._metadata)
2069
+
2070
+ async def list_authorizations(self, org_id: str, resource_ids: Optional[List[str]] = None) -> List[Authorization]:
2071
+ """List all authorizations under a specific resource (or resources) within the currently authed-to organization. If no resource IDs
2072
+ are provided, all resource authorizations within the organizations are returned.
2073
+
2074
+ ::
2075
+
2076
+ list_of_auths = await cloud.list_authorizations(
2077
+ org_id="<YOUR-ORG-ID>",
2078
+ resource_ids=["1a123456-x1yz-0ab0-a12xyzabc"])
2079
+
2080
+ Args:
2081
+ org_id: The ID of the organization to list authorizations for.
2082
+ resource_ids (Optional[List[str]]): IDs of the resources to retrieve authorizations from.
2083
+ If None, defaults to all resources.
2084
+
2085
+ Raises:
2086
+ GRPCError: If an invalid resource ID is passed.
2087
+
2088
+ Returns:
2089
+ List[viam.proto.app.Authorization]: The list of authorizations.
2090
+
2091
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listauthorizations>`_.
2092
+ """
2093
+ request = ListAuthorizationsRequest(organization_id=org_id, resource_ids=resource_ids)
2094
+ response: ListAuthorizationsResponse = await self._app_client.ListAuthorizations(request, metadata=self._metadata)
2095
+ return list(response.authorizations)
2096
+
2097
+ async def check_permissions(self, permissions: List[AuthorizedPermissions]) -> List[AuthorizedPermissions]:
2098
+ """Checks validity of a list of permissions.
2099
+
2100
+ ::
2101
+
2102
+ from viam.proto.app import AuthorizedPermissions
2103
+
2104
+ # Check whether the entity you're currently authenticated to has permission to control and/or
2105
+ # read logs from robots in the "organization-identifier123" org
2106
+ permissions = [AuthorizedPermissions(resource_type="organization",
2107
+ resource_id="<YOUR-ORG-ID>",
2108
+ permissions=["control_robot",
2109
+ "read_robot_logs"])]
2110
+
2111
+ filtered_permissions = await cloud.check_permissions(permissions)
2112
+
2113
+ Args:
2114
+ permissions (List[viam.proto.app.AuthorizedPermissions]): the permissions to validate
2115
+ (for example, "read_organization", "control_robot")
2116
+
2117
+ Raises:
2118
+ GRPCError: If the list of permissions to validate is empty.
2119
+
2120
+ Returns:
2121
+ List[viam.proto.app.AuthorizedPermissions]: The permissions argument, with invalid permissions filtered out.
2122
+
2123
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#checkpermissions>`_.
2124
+ """
2125
+ request = CheckPermissionsRequest(permissions=permissions)
2126
+ response: CheckPermissionsResponse = await self._app_client.CheckPermissions(request, metadata=self._metadata)
2127
+ return list(response.authorized_permissions)
2128
+
2129
+ async def get_registry_item(self, item_id: str, include_markdown_documentation: bool = False) -> RegistryItem:
2130
+ """Get registry item by ID.
2131
+
2132
+ ::
2133
+
2134
+ item = await cloud.get_registry_item("item-id")
2135
+
2136
+ Args:
2137
+ item_id (str): The ID of the registry item. This is the namespace and name of the item in the
2138
+ form `namespace:name`. For example, `Viam's csi-cam-pi module's <https://app.viam.com/module/viam/csi-cam-pi>`_ item ID
2139
+ would be `viam:csi-cam-pi`. You can also use `org-id:name`. For example,
2140
+ `abc01234-0123-4567-ab12-a11a00a2aa22:training-script`.
2141
+
2142
+ Returns:
2143
+ RegistryItem: The registry item.
2144
+
2145
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getregistryitem>`_.
2146
+ """
2147
+ request = GetRegistryItemRequest(item_id=item_id, include_markdown_documentation=include_markdown_documentation)
2148
+ response: GetRegistryItemResponse = await self._app_client.GetRegistryItem(request, metadata=self._metadata)
2149
+ return response.item
2150
+
2151
+ async def create_registry_item(self, organization_id: str, name: str, type: PackageType.ValueType) -> None:
2152
+ """Create a registry item
2153
+
2154
+ ::
2155
+
2156
+ from viam.proto.app.packages import PackageType
2157
+
2158
+ await cloud.create_registry_item("<YOUR-ORG-ID>", "name", PackageType.PACKAGE_TYPE_ML_MODEL)
2159
+
2160
+ Args:
2161
+ organization_id (str): The organization to create the registry item under.
2162
+ name (str): The name of the registry item, which must be unique within your org.
2163
+ type (PackageType.ValueType): The type of the item in the registry.
2164
+
2165
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createregistryitem>`_.
2166
+ """
2167
+ request = CreateRegistryItemRequest(organization_id=organization_id, name=name, type=type)
2168
+ await self._app_client.CreateRegistryItem(request, metadata=self._metadata)
2169
+
2170
+ async def update_registry_item(
2171
+ self, item_id: str, type: PackageType.ValueType, description: str, visibility: Visibility.ValueType
2172
+ ) -> None:
2173
+ """Update a registry item.
2174
+
2175
+ ::
2176
+
2177
+ from viam.proto.app.packages import PackageType
2178
+ from viam.proto.app import Visibility
2179
+
2180
+ await cloud.update_registry_item(
2181
+ "your-namespace:your-name",
2182
+ PackageType.PACKAGE_TYPE_ML_TRAINING,
2183
+ "description",
2184
+ Visibility.VISIBILITY_PUBLIC
2185
+ )
2186
+
2187
+ Args:
2188
+ item_id (str): The ID of the registry item, containing either the namespace and module name
2189
+ (for example, `my-org:my-module`) or organization ID and module name (`org-id:my-module`).
2190
+ type (PackageType.ValueType): The type of the item in the registry.
2191
+ description (str): The description of the registry item.
2192
+ visibility (Visibility.ValueType): The visibility of the registry item.
2193
+
2194
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updateregistryitem>`_.
2195
+ """
2196
+
2197
+ request = UpdateRegistryItemRequest(item_id=item_id, type=type, description=description, visibility=visibility)
2198
+ await self._app_client.UpdateRegistryItem(request, metadata=self._metadata)
2199
+
2200
+ async def list_registry_items(
2201
+ self,
2202
+ organization_id: str,
2203
+ types: List[PackageType.ValueType],
2204
+ visibilities: List[Visibility.ValueType],
2205
+ platforms: List[str],
2206
+ statuses: List[RegistryItemStatus.ValueType],
2207
+ search_term: Optional[str] = None,
2208
+ page_token: Optional[str] = None,
2209
+ ) -> List[RegistryItem]:
2210
+ """List the registry items in an organization.
2211
+
2212
+ ::
2213
+
2214
+ from viam.proto.app.packages import PackageType
2215
+ from viam.proto.app import Visibility, RegistryItemStatus
2216
+
2217
+ # List private, published ml training scripts in your organization
2218
+ registry_items = await cloud.list_registry_items(
2219
+ organization_id="<YOUR-ORG-ID>",
2220
+ types=[PackageType.PACKAGE_TYPE_ML_TRAINING],
2221
+ visibilities=[Visibility.VISIBILITY_PRIVATE],
2222
+ platforms=[""],
2223
+ statuses=[RegistryItemStatus.REGISTRY_ITEM_STATUS_PUBLISHED]
2224
+ )
2225
+
2226
+ # List public, published linux modules in all organizations
2227
+ registry_items = await cloud.list_registry_items(
2228
+ organization_id="",
2229
+ types=[PackageType.PACKAGE_TYPE_MODULE],
2230
+ visibilities=[Visibility.VISIBILITY_PUBLIC],
2231
+ platforms=["linux/any"],
2232
+ statuses=[RegistryItemStatus.REGISTRY_ITEM_STATUS_PUBLISHED]
2233
+ )
2234
+
2235
+ Args:
2236
+ organization_id (str): The ID of the organization to return registry items for.
2237
+ types (List[PackageType.ValueType]): The types of registry items.
2238
+ visibilities (List[Visibility.ValueType]): The visibilities of registry items.
2239
+ platforms (List[str]): The platforms of registry items.
2240
+ statuses (List[RegistryItemStatus.ValueType]): The types of the items in the registry.
2241
+ search_term (Optional[str]): The search term of the registry items.
2242
+ page_token (Optional[str]): The page token of the registry items.
2243
+
2244
+ Returns:
2245
+ List[RegistryItem]: The list of registry items.
2246
+
2247
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listregistryitems>`_.
2248
+ """
2249
+ request = ListRegistryItemsRequest(
2250
+ organization_id=organization_id,
2251
+ types=types,
2252
+ visibilities=visibilities,
2253
+ platforms=platforms,
2254
+ statuses=statuses,
2255
+ search_term=search_term if search_term is not None else "",
2256
+ page_token=page_token if page_token is not None else "",
2257
+ )
2258
+ response: ListRegistryItemsResponse = await self._app_client.ListRegistryItems(request, metadata=self._metadata)
2259
+ return list(response.items)
2260
+
2261
+ async def delete_registry_item(self, item_id: str) -> None:
2262
+ """Delete a registry item
2263
+
2264
+ ::
2265
+
2266
+ await cloud.delete_registry_item("your-namespace:your-name")
2267
+
2268
+ Args:
2269
+ item_id (str): The ID of the deleted registry item, containing either the namespace and module name
2270
+ (for example, `my-org:my-module`) or organization ID and module name (`org-id:my-module`).
2271
+
2272
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deleteregistryitem>`_.
2273
+ """
2274
+ request = DeleteRegistryItemRequest(item_id=item_id)
2275
+ await self._app_client.DeleteRegistryItem(request, metadata=self._metadata)
2276
+
2277
+ async def create_module(self, org_id: str, name: str) -> Tuple[str, str]:
2278
+ """Create a module under the currently authed-to organization.
2279
+
2280
+ ::
2281
+
2282
+ new_module = await cloud.create_module(org_id="org-id", name="cool_new_hoverboard_module")
2283
+ print("Module ID:", new_module[0])
2284
+
2285
+ Args:
2286
+ org_id (str): The ID of the organization to create the module under.
2287
+ You can obtain your organization ID from the organization settings page.
2288
+ name (str): The name of the module. Must be unique within your organization.
2289
+
2290
+ Raises:
2291
+ GRPCError: If an invalid name (for example, "") is passed.
2292
+
2293
+ Returns:
2294
+ Tuple[str, str]: A tuple containing the ID [0] of the new module and its URL [1].
2295
+
2296
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createmodule>`_.
2297
+ """
2298
+ request = CreateModuleRequest(organization_id=org_id, name=name)
2299
+ response: CreateModuleResponse = await self._app_client.CreateModule(request, metadata=self._metadata)
2300
+ return response.module_id, response.url
2301
+
2302
+ async def update_module(
2303
+ self,
2304
+ module_id: str,
2305
+ url: str,
2306
+ description: str,
2307
+ models: Optional[List[Model]],
2308
+ entrypoint: str,
2309
+ public: bool = False,
2310
+ ) -> str:
2311
+ """Update the documentation URL, description, models, entrypoint, and/or the visibility of a module.
2312
+
2313
+ ::
2314
+
2315
+ from viam.proto.app import Model
2316
+
2317
+ model = Model(
2318
+ api="rdk:component:base",
2319
+ model="my-group:cool_new_hoverboard_module:wheeled"
2320
+ )
2321
+
2322
+ url_of_my_module = await cloud.update_module(
2323
+ module_id="my-group:cool_new_hoverboard_module",
2324
+ url="https://docsformymodule.viam.com",
2325
+ models=[model],
2326
+ description="A base to support hoverboards.",
2327
+ entrypoint="exec"
2328
+ )
2329
+
2330
+ Args:
2331
+ module_id (str): ID of the module being updated, containing either the namespace and module name
2332
+ (for example, `my-org:my-module`) or organization ID and module name (`org-id:my-module`).
2333
+ url (str): The url to reference for documentation and code (NOT the url of the module itself).
2334
+ description (str): A short description of the module that explains its purpose.
2335
+ models (List[viam.proto.app.Model]): list of models that are available in the module.
2336
+ entrypoint (str): The executable to run to start the module program.
2337
+ public (bool): The visibility that should be set for the module. Defaults to False (private).
2338
+
2339
+ Raises:
2340
+ GRPCError: If either an invalid module ID, URL, list of models, or organization ID is passed.
2341
+
2342
+ Returns:
2343
+ str: The URL of the newly updated module.
2344
+
2345
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#updatemodule>`_.
2346
+ """
2347
+ request = UpdateModuleRequest(
2348
+ module_id=module_id,
2349
+ visibility=Visibility.VISIBILITY_PUBLIC if public else Visibility.VISIBILITY_PRIVATE,
2350
+ url=url,
2351
+ description=description,
2352
+ models=models,
2353
+ entrypoint=entrypoint,
2354
+ )
2355
+ response: UpdateModuleResponse = await self._app_client.UpdateModule(request, metadata=self._metadata)
2356
+ return response.url
2357
+
2358
+ async def upload_module_file(self, module_file_info: Optional[ModuleFileInfo], file: bytes) -> str:
2359
+ """Upload a module file
2360
+
2361
+ ::
2362
+
2363
+ from viam.proto.app import ModuleFileInfo
2364
+
2365
+ module_file_info = ModuleFileInfo(
2366
+ module_id = "sierra:cool_new_hoverboard_module",
2367
+ version = "1.0.0",
2368
+ platform = "darwin/arm64"
2369
+ )
2370
+
2371
+ file_id = await cloud.upload_module_file(
2372
+ module_file_info=module_file_info,
2373
+ file=b"<file>"
2374
+ )
2375
+
2376
+ Args:
2377
+ module_file_info (Optional[viam.proto.app.ModuleFileInfo]): Relevant metadata.
2378
+ file (bytes): Bytes of file to upload.
2379
+
2380
+ Returns:
2381
+ str: URL of uploaded file.
2382
+
2383
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#uploadmodulefile>`_.
2384
+ """
2385
+ request_module_file_info = UploadModuleFileRequest(module_file_info=module_file_info)
2386
+ request_file = UploadModuleFileRequest(file=file)
2387
+ async with self._app_client.UploadModuleFile.open(metadata=self._metadata) as stream:
2388
+ await stream.send_message(request_module_file_info)
2389
+ await stream.send_message(request_file, end=True)
2390
+ response: Union[UploadModuleFileRequest, None] = await stream.recv_message()
2391
+ if not response:
2392
+ await stream.recv_trailing_metadata() # causes us to throw appropriate gRPC error.
2393
+ raise TypeError("Response cannot be empty") # we should never get here, but for typechecking
2394
+ return response.url
2395
+
2396
+ async def get_module(self, module_id: str) -> Module:
2397
+ """Get a module.
2398
+
2399
+ ::
2400
+
2401
+ the_module = await cloud.get_module(module_id="my-group:my-cool-modular-base")
2402
+
2403
+ Args:
2404
+ module_id (str): ID of the module being retrieved, containing either the namespace and module name
2405
+ (for example, `my-org:my-module`) or organization ID and module name (`org-id:my-module`).
2406
+
2407
+ Raises:
2408
+ GRPCError: If an invalid module ID is passed.
2409
+
2410
+ Returns:
2411
+ viam.proto.app.Module: The module.
2412
+
2413
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#getmodule>`_.
2414
+ """
2415
+ request = GetModuleRequest(module_id=module_id)
2416
+ response: GetModuleResponse = await self._app_client.GetModule(request, metadata=self._metadata)
2417
+ return response.module
2418
+
2419
+ async def list_modules(self, org_id: str) -> List[Module]:
2420
+ """List the modules under the currently authed-to organization.
2421
+
2422
+ ::
2423
+
2424
+ modules_list = await cloud.list_modules("<YOUR-ORG-ID>")
2425
+
2426
+ Args:
2427
+ org_id (str): The ID of the organization to list modules for.
2428
+ You can obtain your organization ID from the organization settings page.
2429
+
2430
+ Returns:
2431
+ List[viam.proto.app.Module]: The list of modules.
2432
+
2433
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listmodules>`_.
2434
+ """
2435
+ request = ListModulesRequest(organization_id=org_id)
2436
+ response: ListModulesResponse = await self._app_client.ListModules(request, metadata=self._metadata)
2437
+ return list(response.modules)
2438
+
2439
+ # TODO(RSDK-5569): when user-based auth exists, make `name` default to `None` and let
2440
+ # app deal with setting a default.
2441
+ async def create_key(self, org_id: str, authorizations: List[APIKeyAuthorization], name: Optional[str] = None) -> Tuple[str, str]:
2442
+ """Creates a new API key.
2443
+
2444
+ ::
2445
+
2446
+ from viam.app.app_client import APIKeyAuthorization
2447
+
2448
+ auth = APIKeyAuthorization(
2449
+ role="owner",
2450
+ resource_type="robot",
2451
+ resource_id="your-machine-id123"
2452
+ )
2453
+
2454
+ api_key, api_key_id = cloud.create_key(
2455
+ org_id="<YOUR-ORG-ID>",
2456
+ authorizations=[auth],
2457
+ name="my_key"
2458
+ )
2459
+
2460
+ Args:
2461
+ org_id (str): The ID of the organization to create the key for.
2462
+ You can obtain your organization ID from the organization settings page.
2463
+ authorizations (List[viam.proto.app.Authorization]): A list of authorizations to associate
2464
+ with the key.
2465
+ name (Optional[str]): A name for the key. If None, defaults to the current timestamp.
2466
+
2467
+ Raises:
2468
+ GRPCError: If the authorizations list is empty.
2469
+
2470
+ Returns:
2471
+ Tuple[str, str]: The api key and api key ID.
2472
+
2473
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createkey>`_.
2474
+ """
2475
+ name = name if name is not None else str(datetime.now())
2476
+ authorizations_pb = [await self._create_authorization_for_new_api_key(org_id, auth) for auth in authorizations]
2477
+ request = CreateKeyRequest(authorizations=authorizations_pb, name=name)
2478
+ response: CreateKeyResponse = await self._app_client.CreateKey(request, metadata=self._metadata)
2479
+ return (response.key, response.id)
2480
+
2481
+ async def delete_key(self, id: str) -> None:
2482
+ """Delete a API key.
2483
+
2484
+ ::
2485
+
2486
+ await cloud.delete_key("key-id")
2487
+
2488
+ Args:
2489
+ id (str): The ID of the API key.
2490
+
2491
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#deletekey>`_.
2492
+ """
2493
+ request = DeleteKeyRequest(id=id)
2494
+ await self._app_client.DeleteKey(request, metadata=self._metadata)
2495
+
2496
+ async def create_key_from_existing_key_authorizations(self, id: str) -> Tuple[str, str]:
2497
+ """Creates a new API key with an existing key's authorizations
2498
+
2499
+ ::
2500
+
2501
+ api_key, api_key_id = await cloud.create_key_from_existing_key_authorizations(
2502
+ id="INSERT YOUR API KEY ID")
2503
+
2504
+ Args:
2505
+ id (str): the ID of the API key to duplication authorizations from
2506
+
2507
+ Returns:
2508
+ Tuple[str, str]: The API key and API key id
2509
+
2510
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#createkeyfromexistingkeyauthorizations>`_.
2511
+ """
2512
+ request = CreateKeyFromExistingKeyAuthorizationsRequest(id=id)
2513
+ response: CreateKeyFromExistingKeyAuthorizationsResponse = await self._app_client.CreateKeyFromExistingKeyAuthorizations(
2514
+ request,
2515
+ metadata=self._metadata,
2516
+ )
2517
+ return (response.key, response.id)
2518
+
2519
+ async def list_keys(self, org_id: str) -> List[APIKeyWithAuthorizations]:
2520
+ """Lists all keys for the currently-authed-to org.
2521
+
2522
+ ::
2523
+
2524
+ keys = await cloud.list_keys(org_id="<YOUR-ORG-ID>")
2525
+
2526
+ Args:
2527
+ org_id (str): The ID of the organization to list API keys for.
2528
+ You can obtain your organization ID from the organization settings page.
2529
+
2530
+ Returns:
2531
+ List[viam.proto.app.APIKeyWithAuthorizations]: The existing API keys and authorizations.
2532
+
2533
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#listkeys>`_.
2534
+ """
2535
+ request = ListKeysRequest(org_id=org_id)
2536
+ response: ListKeysResponse = await self._app_client.ListKeys(request, metadata=self._metadata)
2537
+ return list(response.api_keys)
2538
+
2539
+ async def rotate_key(self, id: str) -> Tuple[str, str]:
2540
+ """Rotate an API key.
2541
+
2542
+ ::
2543
+
2544
+ key, id = await cloud.rotate_key("key-id")
2545
+
2546
+ Args:
2547
+ id (str): The ID of the key to be rotated.
2548
+
2549
+ Returns:
2550
+ Tuple[str, str]: The API key and API key id
2551
+
2552
+ For more information, see `Fleet Management API <https://docs.viam.com/dev/reference/apis/fleet/#rotatekey>`_.
2553
+ """
2554
+ request = RotateKeyRequest(id=id)
2555
+ response: RotateKeyResponse = await self._app_client.RotateKey(request, metadata=self._metadata)
2556
+ return response.key, response.id
2557
+
2558
+ async def get_organization_metadata(self, org_id: str) -> Mapping[str, Any]:
2559
+ """Get an organization's user-defined metadata.
2560
+
2561
+ ::
2562
+
2563
+ metadata = await cloud.get_organization_metadata(org_id="<YOUR-ORG-ID>")
2564
+
2565
+ Args:
2566
+ org_id (str): The ID of the organization with which the user-defined metadata is associated.
2567
+ You can obtain your organization ID from the organization settings page.
2568
+
2569
+ Returns:
2570
+ Mapping[str, Any]: The user-defined metadata converted from JSON to a Python dictionary
2571
+ """
2572
+ request = GetOrganizationMetadataRequest(organization_id=org_id)
2573
+ response: GetOrganizationMetadataResponse = await self._app_client.GetOrganizationMetadata(request, metadata=self._metadata)
2574
+ return struct_to_dict(response.data)
2575
+
2576
+ async def update_organization_metadata(self, org_id: str, metadata: Mapping[str, Any]) -> None:
2577
+ """Update an organization's user-defined metadata.
2578
+
2579
+ ::
2580
+
2581
+ await cloud.update_organization_metadata(org_id="<YOUR-ORG-ID>", metadata={
2582
+ "TEST_API_KEY": "ABC123",
2583
+ })
2584
+
2585
+ Args:
2586
+ organization_id (str): The ID of the organization with which to associate the user-defined metadata.
2587
+ You can obtain your organization ID from the organization settings page.
2588
+ metadata (Mapping[str, Any]): The user-defined metadata to upload as a Python dictionary.
2589
+ """
2590
+ request = UpdateOrganizationMetadataRequest(organization_id=org_id, data=dict_to_struct(metadata))
2591
+ _: UpdateOrganizationMetadataResponse = await self._app_client.UpdateOrganizationMetadata(request, metadata=self._metadata)
2592
+
2593
+ async def get_location_metadata(self, location_id: str) -> Mapping[str, Any]:
2594
+ """Get a location's user-defined metadata.
2595
+
2596
+ ::
2597
+
2598
+ metadata = await cloud.get_location_metadata(location_id="<YOUR-LOCATION-ID>")
2599
+
2600
+ Args:
2601
+ location_id (str): The ID of the location with which the user-defined metadata is associated.
2602
+ You can obtain your location ID from the location's page.
2603
+
2604
+ Returns:
2605
+ Mapping[str, Any]: The user-defined metadata converted from JSON to a Python dictionary.
2606
+ """
2607
+ request = GetLocationMetadataRequest(location_id=location_id)
2608
+ response: GetLocationMetadataResponse = await self._app_client.GetLocationMetadata(request, metadata=self._metadata)
2609
+ return struct_to_dict(response.data)
2610
+
2611
+ async def update_location_metadata(self, location_id: str, metadata: Mapping[str, Any]) -> None:
2612
+ """Update a location's user-defined metadata.
2613
+
2614
+ ::
2615
+
2616
+ await cloud.update_location_metadata(location_id="<YOUR-LOCATION-ID>", metadata={
2617
+ "TEST_API_KEY": "ABC123",
2618
+ })
2619
+
2620
+ Args:
2621
+ location_id (str): The ID of the location with which to associate the user-defined metadata.
2622
+ You can obtain your location ID from the location's page.
2623
+ metadata (Mapping[str, Any]): The user-defined metadata converted from JSON to a Python dictionary.
2624
+ """
2625
+ request = UpdateLocationMetadataRequest(location_id=location_id, data=dict_to_struct(metadata))
2626
+ _: UpdateLocationMetadataResponse = await self._app_client.UpdateLocationMetadata(request, metadata=self._metadata)
2627
+
2628
+ async def get_robot_metadata(self, robot_id: str) -> Mapping[str, Any]:
2629
+ """Get a robot's user-defined metadata.
2630
+
2631
+ ::
2632
+
2633
+ metadata = await cloud.get_robot_metadata(robot_id="<YOUR-ROBOT-ID>")
2634
+
2635
+ Args:
2636
+ robot_id (str): The ID of the robot with which the user-defined metadata is associated.
2637
+ You can obtain your robot ID from the machine page.
2638
+
2639
+ Returns:
2640
+ Mapping[str, Any]: The user-defined metadata converted from JSON to a Python dictionary.
2641
+ """
2642
+ request = GetRobotMetadataRequest(id=robot_id)
2643
+ response: GetRobotMetadataResponse = await self._app_client.GetRobotMetadata(request, metadata=self._metadata)
2644
+ return struct_to_dict(response.data)
2645
+
2646
+ async def update_robot_metadata(self, robot_id: str, metadata: Mapping[str, Any]) -> None:
2647
+ """Update a robot's user-defined metadata.
2648
+
2649
+ ::
2650
+
2651
+ await cloud.update_robot_metadata(robot_id="<YOUR-ROBOT-ID>", metadata={
2652
+ "TEST_API_KEY": "ABC123",
2653
+ })
2654
+
2655
+ Args:
2656
+ robot_id (str): The ID of the robot with which to associate the user-defined metadata.
2657
+ You can obtain your robot ID from the machine page.
2658
+ metadata (Mapping[str, Any]): The user-defined metadata converted from JSON to a Python dictionary.
2659
+ """
2660
+ request = UpdateRobotMetadataRequest(id=robot_id, data=dict_to_struct(metadata))
2661
+ _: UpdateRobotMetadataResponse = await self._app_client.UpdateRobotMetadata(request, metadata=self._metadata)
2662
+
2663
+ async def get_robot_part_metadata(self, robot_part_id: str) -> Mapping[str, Any]:
2664
+ """Get a robot part's user-defined metadata.
2665
+
2666
+ ::
2667
+
2668
+ metadata = await cloud.get_robot_part_metadata(robot_part_id="<YOUR-ROBOT-PART-ID>")
2669
+
2670
+ Args:
2671
+ robot_part_id (str): The ID of the robot part with which the user-defined metadata is associated.
2672
+ You can obtain your robot part ID from the machine page.
2673
+
2674
+ Returns:
2675
+ Mapping[str, Any]: The user-defined metadata converted from JSON to a Python dictionary.
2676
+ """
2677
+ request = GetRobotPartMetadataRequest(id=robot_part_id)
2678
+ response: GetRobotPartMetadataResponse = await self._app_client.GetRobotPartMetadata(request, metadata=self._metadata)
2679
+ return struct_to_dict(response.data)
2680
+
2681
+ async def update_robot_part_metadata(self, robot_part_id: str, metadata: Mapping[str, Any]) -> None:
2682
+ """Update a robot part's user-defined metadata.
2683
+
2684
+ ::
2685
+
2686
+ await cloud.update_robot_part_metadata(robot_part_id="<YOUR-ROBOT-PART-ID>", metadata={
2687
+ "TEST_API_KEY": "ABC123",
2688
+ })
2689
+
2690
+ Args:
2691
+ robot_id (str): The ID of the robot part with which to associate the user-defined metadata.
2692
+ You can obtain your robot part ID from the machine page.
2693
+ metadata (Mapping[str, Any]): The user-defined metadata converted from JSON to a Python dictionary.
2694
+ """
2695
+ request = UpdateRobotPartMetadataRequest(id=robot_part_id, data=dict_to_struct(metadata))
2696
+ _: UpdateRobotPartMetadataResponse = await self._app_client.UpdateRobotPartMetadata(request, metadata=self._metadata)