standardbots 2.20250512.15__tar.gz → 2.20250923.36__tar.gz

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 standardbots might be problematic. Click here for more details.

Files changed (18) hide show
  1. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/PKG-INFO +1 -1
  2. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/README.md +38 -22
  3. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/setup.py +1 -1
  4. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots/auto_generated/apis.py +298 -1
  5. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots/auto_generated/models.py +1423 -233
  6. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots.egg-info/PKG-INFO +1 -1
  7. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/tests/test_apis.py +71 -29
  8. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/setup.cfg +0 -0
  9. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots/__init__.py +0 -0
  10. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots/auto_generated/__init__.py +0 -0
  11. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots.egg-info/SOURCES.txt +0 -0
  12. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots.egg-info/dependency_links.txt +0 -0
  13. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots.egg-info/requires.txt +0 -0
  14. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/standardbots.egg-info/top_level.txt +0 -0
  15. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/tests/fixtures/__init__.py +0 -0
  16. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/tests/fixtures/client_fixt.py +0 -0
  17. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/tests/fixtures/robot_fixt.py +0 -0
  18. {standardbots-2.20250512.15 → standardbots-2.20250923.36}/tests/fixtures/routines_fixt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: standardbots
3
- Version: 2.20250512.15
3
+ Version: 2.20250923.36
4
4
  Summary: Standard Bots RO1 Robotics API
5
5
  Home-page:
6
6
  Author: Standard Bots Support
@@ -1,9 +1,11 @@
1
- You can test the API by using the playground, add your own file or use the existing python scripts.
2
- When a client has an issue, and they send their code. It's helpful to test their code to see possible issues
1
+ You can test the API by using the playground, add your own file or use the
2
+ existing python scripts. When a client has an issue, and they send their code.
3
+ It's helpful to test their code to see possible issues
3
4
 
4
5
  # ENABLE API ON YOUR LOCAL MACHINE
5
6
 
6
- Follow the steps here https://www.notion.so/standardbots/Using-the-REST-API-b2c778d47969444dac61483f0117acad
7
+ Follow the steps here
8
+ https://www.notion.so/standardbots/Using-the-REST-API-b2c778d47969444dac61483f0117acad
7
9
 
8
10
  # CONFIG
9
11
 
@@ -11,7 +13,8 @@ At the top of the file, use your token
11
13
 
12
14
  # RUN
13
15
 
14
- To run a script move into the `sdks/python` folder and run `python playground/filename.py`
16
+ To run a script move into the `sdks/python` folder and run
17
+ `python playground/filename.py`
15
18
 
16
19
  # To create a test build
17
20
 
@@ -48,8 +51,8 @@ To set up tests:
48
51
  cd sdks/python
49
52
  ```
50
53
 
51
- Note: Make sure to select proper python interpreter.
52
- Sometimes there is an error related to missing "dotenv" module, to solve this install it separately
54
+ Note: Make sure to select proper python interpreter. Sometimes there is an error
55
+ related to missing "dotenv" module, to solve this install it separately
53
56
 
54
57
  ```
55
58
  python3 -m pip install python-dotenv
@@ -60,16 +63,18 @@ python3 -m pip install -r requirements-dev.txt
60
63
 
61
64
  #### Sample routine
62
65
 
63
- You need to add the sample routine in [sdks/python/tests/fixtures/test_public_api_routine.json](./tests/fixtures/test_public_api_routine.json) to your target test environment (i.e. upload the routine to ).
66
+ You need to add the sample routine in
67
+ [sdks/python/tests/fixtures/test_public_api_routine.json](./tests/fixtures/test_public_api_routine.json)
68
+ to your target test environment (i.e. upload the routine to ).
64
69
 
65
70
  The name of routine should be "Test Public API"
66
71
 
67
72
  #### Sample globals
68
73
 
69
- - _Variable._ Add global variable called "test_public_api_global" with any value.
74
+ - _Variable._ Add global variable called "test_public_api_global" with any
75
+ value.
70
76
  - _Space._ Create a global space called "Test global space" of any kind.
71
77
 
72
-
73
78
  ## Running
74
79
 
75
80
  Here is a basic test command:
@@ -81,7 +86,8 @@ SB_API_TOKEN=...
81
86
  python3 -m pytest ./tests --cov=standardbots --token=$SB_API_TOKEN --api-url=$SB_API_URL
82
87
  ```
83
88
 
84
- You may also set up a `.env` file at `sdks/python/.env` with the following contents:
89
+ You may also set up a `.env` file at `sdks/python/.env` with the following
90
+ contents:
85
91
 
86
92
  ```bash
87
93
  export SB_API_URL=http://34.162.0.32:3000
@@ -96,38 +102,43 @@ python3 -m pytest ./tests --cov=standardbots
96
102
 
97
103
  ### Robot state and testing (Markers)
98
104
 
99
- We need the bot to be in a certain state to run certain tests. For example, we need a routine to be running in order to stop the routine. Camera should be connected by default.
105
+ We need the bot to be in a certain state to run certain tests. For example, we
106
+ need a routine to be running in order to stop the routine. Camera should be
107
+ disconnected by default.
100
108
 
101
109
  At start of testing, robot should:
102
110
 
103
111
  - _NOT_ be e-stopped.
104
112
 
105
-
106
113
  The basic idea here is:
107
114
 
108
115
  - These special tests will not be run by default.
109
- - You may pass a flag (e.g. `--camera-disconnected`) when the bot is in the correct state to run the tests.
116
+ - You may pass a flag (e.g. `--camera-connected`) when the bot is in the correct
117
+ state to run the tests.
110
118
  - Markers usage:
111
- - When `--gripper=<type>` flag is passed(`type` is value from `GripperKindEnum` enum):
119
+ - When `--gripper=<type>` flag is passed(`type` is value from `GripperKindEnum`
120
+ enum):
112
121
  1. Tests expect that this specific gripper is connected
113
122
  2. Tests without the flag are not run.
114
- - When `--camera-disconnected` flag is passed:
123
+ - When `--camera-connected` flag is passed:
115
124
  1. Tests with the flag are run.
116
125
  2. Tests without the flag are not run.
117
126
 
118
- We use [pytest markers](https://docs.pytest.org/en/7.1.x/example/markers.html) to do this.
127
+ We use [pytest markers](https://docs.pytest.org/en/7.1.x/example/markers.html)
128
+ to do this.
119
129
 
120
130
  #### Camera disconnected
121
131
 
122
132
  The wrist camera should be disabled. Then run:
123
133
 
124
134
  ```bash
125
- python3 -m pytest ./tests --cov=standardbots --camera-disconnected
135
+ python3 -m pytest ./tests --cov=standardbots --camera-connected
126
136
  ```
127
137
 
128
138
  #### E-stop
129
139
 
130
- No marker needed for e-stop. However, we do rely on active recovery of e-stop and getting the failure state in order to do these tests.
140
+ No marker needed for e-stop. However, we do rely on active recovery of e-stop
141
+ and getting the failure state in order to do these tests.
131
142
 
132
143
  When e-stop test runs, cannot have bot in a failure state (pre-test will fail).
133
144
 
@@ -151,16 +162,19 @@ tests/test_apis.py
151
162
  Fixes:
152
163
 
153
164
  - _Make sure you can log into remote control._ Ensure that botman is connected.
154
- - _Ensure that the robot URL is up-to-date._ Botman url will often change when you reboot.
165
+ - _Ensure that the robot URL is up-to-date._ Botman url will often change when
166
+ you reboot.
155
167
 
156
168
  ### Custom sensors
157
169
 
158
170
  To test custom sensors:
171
+
159
172
  - go to the menu on the left bottom corner;
160
173
  - Click on 'Equipment';
161
174
  - Add Gripper > Custom Gripper;
162
175
  - Go to the Sensors tab and click 'Add Sensor';
163
- - Keep the default values as they are (name: 'Sensor 1', kind: 'Control Box IO', sensor value: 'low');
176
+ - Keep the default values as they are (name: 'Sensor 1', kind: 'Control Box IO',
177
+ sensor value: 'low');
164
178
  - Hit 'Save' and make sure the Custom Gripper is enabled.
165
179
 
166
180
  Then run:
@@ -173,11 +187,13 @@ python3 -m pytest ./tests --cov=standardbots --gripper=custom_sensors
173
187
 
174
188
  > See command: `botctl publicapi test:setup-bot`.
175
189
 
176
- We now have a common robot database state that can be used for testing. While this isn't necessary for use, it does provide a common state for testing.
190
+ We now have a common robot database state that can be used for testing. While
191
+ this isn't necessary for use, it does provide a common state for testing.
177
192
 
178
193
  ### How to create a new backup
179
194
 
180
- In the place where you are running the stack and want to create the backup (e.g. on the control box):
195
+ In the place where you are running the stack and want to create the backup (e.g.
196
+ on the control box):
181
197
 
182
198
  ```bash
183
199
  DB_USER=sb
@@ -13,7 +13,7 @@
13
13
  from setuptools import setup, find_packages # noqa: H301
14
14
 
15
15
  NAME = "standardbots"
16
- VERSION = "2.20250512.15"
16
+ VERSION = "2.20250923.36"
17
17
  # To install the library, run the following
18
18
  #
19
19
  # python setup.py install
@@ -284,6 +284,50 @@ class Default:
284
284
  )
285
285
 
286
286
 
287
+ def get_equipment(
288
+ self,
289
+ ) -> Response[
290
+ Union[
291
+ models.GetEquipmentConfigResponse,
292
+ models.ErrorResponse,
293
+ None
294
+ ],
295
+ models.GetEquipmentConfigResponse
296
+ ]:
297
+ """
298
+ Get the currently-configured equipment
299
+
300
+ """
301
+ path = "/api/v1/equipment"
302
+ try:
303
+ response = self._request_manager.request(
304
+ "GET",
305
+ path,
306
+ headers=self._request_manager.json_headers(),
307
+ )
308
+ parsed = None
309
+ if response.status == 200:
310
+ parsed = models.parse_get_equipment_config_response(json.loads(response.data))
311
+
312
+ is_user_error = response.status >= 400 and response.status <= 500
313
+ is_unavailable = response.status == 503
314
+ if parsed is None and (is_user_error or is_unavailable):
315
+ parsed = models.parse_error_response(json.loads(response.data))
316
+
317
+ return Response(
318
+ parsed,
319
+ response.status,
320
+ response
321
+ )
322
+ except urllib3.exceptions.MaxRetryError:
323
+ return Response(
324
+ models.ErrorResponse(
325
+ error=models.ErrorEnum.InternalServerError,
326
+ message="Connection Refused"
327
+ ),
328
+ 503,
329
+ None
330
+ )
287
331
  def control_gripper(
288
332
  self,
289
333
  body: models.GripperCommandRequest,
@@ -1074,7 +1118,7 @@ class Default:
1074
1118
  models.TeleopState
1075
1119
  ]:
1076
1120
  """
1077
- Set ratio control parameters
1121
+ Set ratio control parameters for movement and rotation
1078
1122
  """
1079
1123
  path = "/api/v1/teleop/set-ratio-control"
1080
1124
  try:
@@ -1107,6 +1151,99 @@ class Default:
1107
1151
  503,
1108
1152
  None
1109
1153
  )
1154
+ class Webrtc:
1155
+ def __init__(self, request_manager: RequestManager):
1156
+ self._request_manager = request_manager
1157
+
1158
+
1159
+ def send_message(
1160
+ self,
1161
+ body: models.SendMessageRequest,
1162
+ ) -> Response[
1163
+ None,
1164
+ None
1165
+ ]:
1166
+ """
1167
+ Send a WebRTC signaling message
1168
+ """
1169
+ path = "/api/v1/webrtc/message"
1170
+ try:
1171
+ response = self._request_manager.request(
1172
+ "POST",
1173
+ path,
1174
+ headers=self._request_manager.json_headers(),
1175
+ body=json.dumps(models.serialize_send_message_request(body)),
1176
+ )
1177
+ parsed = None
1178
+
1179
+ is_user_error = response.status >= 400 and response.status <= 500
1180
+ is_unavailable = response.status == 503
1181
+ if parsed is None and (is_user_error or is_unavailable):
1182
+ parsed = models.parse_error_response(json.loads(response.data))
1183
+
1184
+ return Response(
1185
+ parsed,
1186
+ response.status,
1187
+ response
1188
+ )
1189
+ except urllib3.exceptions.MaxRetryError:
1190
+ return Response(
1191
+ models.ErrorResponse(
1192
+ error=models.ErrorEnum.InternalServerError,
1193
+ message="Connection Refused"
1194
+ ),
1195
+ 503,
1196
+ None
1197
+ )
1198
+ def get_messages(
1199
+ self,
1200
+ base_url: str,
1201
+ client_id: str,
1202
+ ) -> Response[
1203
+ Union[
1204
+ models.GetMessagesResponse,
1205
+ models.ErrorResponse,
1206
+ None
1207
+ ],
1208
+ models.GetMessagesResponse
1209
+ ]:
1210
+ """
1211
+ Get pending WebRTC signaling messages
1212
+ """
1213
+ path = "/api/v1/webrtc/messages"
1214
+ try:
1215
+ response = self._request_manager.request(
1216
+ "GET",
1217
+ path,
1218
+ headers=self._request_manager.json_headers(),
1219
+ fields={
1220
+ "baseUrl": models.serialize_str(base_url),
1221
+ "clientId": models.serialize_str(client_id),
1222
+ }
1223
+ )
1224
+ parsed = None
1225
+ if response.status == 200:
1226
+ parsed = models.parse_get_messages_response(json.loads(response.data))
1227
+
1228
+ is_user_error = response.status >= 400 and response.status <= 500
1229
+ is_unavailable = response.status == 503
1230
+ if parsed is None and (is_user_error or is_unavailable):
1231
+ parsed = models.parse_error_response(json.loads(response.data))
1232
+
1233
+ return Response(
1234
+ parsed,
1235
+ response.status,
1236
+ response
1237
+ )
1238
+ except urllib3.exceptions.MaxRetryError:
1239
+ return Response(
1240
+ models.ErrorResponse(
1241
+ error=models.ErrorEnum.InternalServerError,
1242
+ message="Connection Refused"
1243
+ ),
1244
+ 503,
1245
+ None
1246
+ )
1110
1247
 
1111
1248
  calibration: Calibration
1112
1249
  equipment: Equipment
@@ -1115,6 +1252,7 @@ class Default:
1115
1252
  sensors: Sensors
1116
1253
  space: Space
1117
1254
  teleop: Teleop
1255
+ webrtc: Webrtc
1118
1256
 
1119
1257
  def __init__(self, request_manager: RequestManager):
1120
1258
  self._request_manager = request_manager
@@ -1125,6 +1263,7 @@ class Default:
1125
1263
  self.sensors = Default.Sensors(request_manager)
1126
1264
  self.space = Default.Space(request_manager)
1127
1265
  self.teleop = Default.Teleop(request_manager)
1266
+ self.webrtc = Default.Webrtc(request_manager)
1128
1267
 
1129
1268
  class Movement:
1130
1269
  _request_manager: RequestManager
@@ -1753,16 +1892,66 @@ class Camera:
1753
1892
  503,
1754
1893
  None
1755
1894
  )
1895
+ class Bot:
1896
+ def __init__(self, request_manager: RequestManager):
1897
+ self._request_manager = request_manager
1898
+
1899
+
1900
+ def get_connected_cameras(
1901
+ self,
1902
+ ) -> Response[
1903
+ Union[
1904
+ models.CameraDeviceList,
1905
+ models.ErrorResponse,
1906
+ None
1907
+ ],
1908
+ models.CameraDeviceList
1909
+ ]:
1910
+ """
1911
+ Retrieve the list of connected camera devices from camera bot.
1912
+ """
1913
+ path = "/api/v1/cameras/connected"
1914
+ try:
1915
+ response = self._request_manager.request(
1916
+ "GET",
1917
+ path,
1918
+ headers=self._request_manager.json_headers(),
1919
+ )
1920
+ parsed = None
1921
+ if response.status == 200:
1922
+ parsed = models.parse_camera_device_list(json.loads(response.data))
1923
+
1924
+ is_user_error = response.status >= 400 and response.status <= 500
1925
+ is_unavailable = response.status == 503
1926
+ if parsed is None and (is_user_error or is_unavailable):
1927
+ parsed = models.parse_error_response(json.loads(response.data))
1928
+
1929
+ return Response(
1930
+ parsed,
1931
+ response.status,
1932
+ response
1933
+ )
1934
+ except urllib3.exceptions.MaxRetryError:
1935
+ return Response(
1936
+ models.ErrorResponse(
1937
+ error=models.ErrorEnum.InternalServerError,
1938
+ message="Connection Refused"
1939
+ ),
1940
+ 503,
1941
+ None
1942
+ )
1756
1943
 
1757
1944
  data: Data
1758
1945
  settings: Settings
1759
1946
  status: Status
1947
+ bot: Bot
1760
1948
 
1761
1949
  def __init__(self, request_manager: RequestManager):
1762
1950
  self._request_manager = request_manager
1763
1951
  self.data = Camera.Data(request_manager)
1764
1952
  self.settings = Camera.Settings(request_manager)
1765
1953
  self.status = Camera.Status(request_manager)
1954
+ self.bot = Camera.Bot(request_manager)
1766
1955
 
1767
1956
  class Faults:
1768
1957
  _request_manager: RequestManager
@@ -2135,6 +2324,112 @@ class IO:
2135
2324
  self.control = IO.Control(request_manager)
2136
2325
  self.status = IO.Status(request_manager)
2137
2326
 
2327
+ class Messenger:
2328
+ _request_manager: RequestManager
2329
+ class Peers:
2330
+ def __init__(self, request_manager: RequestManager):
2331
+ self._request_manager = request_manager
2332
+
2333
+
2334
+ def register_peer(
2335
+ self,
2336
+ body: models.RegisterPeerRequest,
2337
+ ) -> Response[
2338
+ Union[
2339
+ models.RegisterPeerResponse,
2340
+ models.ErrorResponse,
2341
+ None
2342
+ ],
2343
+ models.RegisterPeerResponse
2344
+ ]:
2345
+ """
2346
+ Register a new peer with the messenger system.
2347
+
2348
+ """
2349
+ path = "/api/v1/messenger/peers"
2350
+ try:
2351
+ response = self._request_manager.request(
2352
+ "POST",
2353
+ path,
2354
+ headers=self._request_manager.json_headers(),
2355
+ body=json.dumps(models.serialize_register_peer_request(body)),
2356
+ )
2357
+ parsed = None
2358
+ if response.status == 200:
2359
+ parsed = models.parse_register_peer_response(json.loads(response.data))
2360
+
2361
+ is_user_error = response.status >= 400 and response.status <= 500
2362
+ is_unavailable = response.status == 503
2363
+ if parsed is None and (is_user_error or is_unavailable):
2364
+ parsed = models.parse_error_response(json.loads(response.data))
2365
+
2366
+ return Response(
2367
+ parsed,
2368
+ response.status,
2369
+ response
2370
+ )
2371
+ except urllib3.exceptions.MaxRetryError:
2372
+ return Response(
2373
+ models.ErrorResponse(
2374
+ error=models.ErrorEnum.InternalServerError,
2375
+ message="Connection Refused"
2376
+ ),
2377
+ 503,
2378
+ None
2379
+ )
2380
+ def unregister_peer(
2381
+ self,
2382
+ body: models.UnregisterPeerRequest,
2383
+ ) -> Response[
2384
+ Union[
2385
+ models.UnregisterPeerResponse,
2386
+ models.ErrorResponse,
2387
+ None
2388
+ ],
2389
+ models.UnregisterPeerResponse
2390
+ ]:
2391
+ """
2392
+ Unregister an existing peer from the messenger system.
2393
+
2394
+ """
2395
+ path = "/api/v1/messenger/peers"
2396
+ try:
2397
+ response = self._request_manager.request(
2398
+ "DELETE",
2399
+ path,
2400
+ headers=self._request_manager.json_headers(),
2401
+ body=json.dumps(models.serialize_unregister_peer_request(body)),
2402
+ )
2403
+ parsed = None
2404
+ if response.status == 200:
2405
+ parsed = models.parse_unregister_peer_response(json.loads(response.data))
2406
+
2407
+ is_user_error = response.status >= 400 and response.status <= 500
2408
+ is_unavailable = response.status == 503
2409
+ if parsed is None and (is_user_error or is_unavailable):
2410
+ parsed = models.parse_error_response(json.loads(response.data))
2411
+
2412
+ return Response(
2413
+ parsed,
2414
+ response.status,
2415
+ response
2416
+ )
2417
+ except urllib3.exceptions.MaxRetryError:
2418
+ return Response(
2419
+ models.ErrorResponse(
2420
+ error=models.ErrorEnum.InternalServerError,
2421
+ message="Connection Refused"
2422
+ ),
2423
+ 503,
2424
+ None
2425
+ )
2426
+
2427
+ peers: Peers
2428
+
2429
+ def __init__(self, request_manager: RequestManager):
2430
+ self._request_manager = request_manager
2431
+ self.peers = Messenger.Peers(request_manager)
2432
+
2138
2433
  class Poses:
2139
2434
  _request_manager: RequestManager
2140
2435
  class ConstructPose:
@@ -3459,6 +3754,7 @@ class StandardBotsRobot(Default):
3459
3754
  general: General
3460
3755
  chat_gpt: ChatGPT
3461
3756
  io: IO
3757
+ messenger: Messenger
3462
3758
  poses: Poses
3463
3759
  recovery: Recovery
3464
3760
  ros: ROS
@@ -3483,6 +3779,7 @@ class StandardBotsRobot(Default):
3483
3779
  self.general = General(self._request_manager)
3484
3780
  self.chat_gpt = ChatGPT(self._request_manager)
3485
3781
  self.io = IO(self._request_manager)
3782
+ self.messenger = Messenger(self._request_manager)
3486
3783
  self.poses = Poses(self._request_manager)
3487
3784
  self.recovery = Recovery(self._request_manager)
3488
3785
  self.ros = ROS(self._request_manager)