Skip to content

Commit f7eab30

Browse files
committed
chore: New release 2.4.6
1 parent fcd256e commit f7eab30

File tree

19 files changed

+187
-60
lines changed

19 files changed

+187
-60
lines changed

exts/wandelbots.omni/config/extension.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[core]
22
reloadable = true
3-
order = 0
3+
order = 1000 # Make sure all .dlls are loaded before this extension
44

55
[package]
6-
version = "2.3.0"
6+
version = "2.4.6"
77
category = "Simulation"
88
title = "Wandelbots NOVA"
99
description = "Simulate your robotics cell running on Wandelbots NOVA."
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
httpx==0.28.1
22
scikit-learn==1.6.1
3-
wandelbots-nova==2.9.0
3+
wandelbots-api-client==25.8.0.dev71
44
python-decouple==3.8
55
tenacity==9.1.2

exts/wandelbots.omni/docs/CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,49 @@
11
# Changelog - Wandelbots NOVA x Nvidia Isaac Sim
22

3+
## 2.4.6 (2025-09-09)
4+
5+
### Bug Fixes
6+
7+
* Fixed missing dll on extension startup
8+
9+
## 2.4.5 (2025-09-06)
10+
11+
### Bug Fixes
12+
13+
* Check compatability on base_version
14+
15+
## 2.4.4 (2025-09-05)
16+
17+
### Bug Fixes
18+
19+
* Update order of environments for authentication
20+
21+
## 2.4.3 (2025-09-05)
22+
23+
### Bug Fixes
24+
25+
* Add default config if no alternative environments are given for authentication.
26+
27+
## 2.4.2 (2025-08-28)
28+
29+
### Bug Fixes
30+
31+
* **RPS-1990:** Fixed choosing proper portal API
32+
33+
## 2.4.1 (2025-08-27)
34+
35+
### Bug Fixes
36+
37+
* Added reset to ogn node config once timeline stops
38+
* Fixed model_name namespace conflict
39+
* Updated portal login to latest api package
40+
41+
## 2.4.0 (2025-08-27)
42+
43+
### Features
44+
45+
* **RPS-1922:** Compatability with 25.8.0
46+
347
## 2.3.0 (2025-08-21)
448

549
### Features

exts/wandelbots.omni/wandelbots/omni/environment.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
)
66
from decouple import Config, RepositoryEnv
77
import os
8+
import toml
89

910
host_database = InMemoryDatabase()
1011
credential_store = CredentialStore()
@@ -27,3 +28,19 @@ def load_env() -> Config:
2728

2829
config = Config(RepositoryEnv(env_path))
2930
return config
31+
32+
33+
def load_config(filename: str = None) -> dict:
34+
if filename is None:
35+
return {}
36+
37+
start_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
38+
config_path = os.path.join(start_path, "config", filename)
39+
if not os.path.isfile(config_path):
40+
return {}
41+
42+
if config_path is None:
43+
return {}
44+
45+
config = toml.load(config_path)
46+
return config

exts/wandelbots.omni/wandelbots/omni/instances/instances_api.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
)
1414
from wandelbots.omni.utils.auth import (
1515
get_auth_token,
16+
get_portal_api_url,
1617
invalidate_auth_token,
17-
get_auth_environment,
1818
)
1919
from wandelbots_api_client.v2.api.cell_api import CellApi
2020
from wandelbots_api_client.v2.api.controller_api import ControllerApi
@@ -25,9 +25,7 @@
2525

2626
class NOVAInstancesAPI:
2727
def __init__(self):
28-
environment = get_auth_environment()
29-
env_prefix = f"{environment}." if environment and environment != "prod" else ""
30-
self._base_url = f"https://api.portal.{env_prefix}wandelbots.io/v1"
28+
self._base_url = get_portal_api_url()
3129

3230
def get_cloud_instances(self) -> list[NOVACloudInstance]:
3331
token = get_auth_token()
@@ -55,7 +53,7 @@ def get_cloud_instances(self) -> list[NOVACloudInstance]:
5553
except requests.HTTPError as e:
5654
if e.response.status_code == 401:
5755
carb.log_warn(
58-
"Authentication token is invalid (401). Invalidating token."
56+
"Authentication token for cloud instances is invalid (401). Invalidating token."
5957
)
6058
invalidate_auth_token()
6159
return []
@@ -140,7 +138,7 @@ def toggle_instance_status(self, instance: NOVACloudInstance):
140138
except requests.HTTPError as e:
141139
if e.response.status_code == 401:
142140
carb.log_warn(
143-
"Authentication token is invalid (401). Invalidating token."
141+
f"Authentication token for host '{instance.host}' is invalid (401). Invalidating token."
144142
)
145143
invalidate_auth_token()
146144
else:
@@ -232,7 +230,7 @@ async def _fetch_single_cell_data(
232230
motion_groups.append(
233231
NOVAMotionGroupData(
234232
name=motion_group_name,
235-
model_name=motion_group_desc.motion_group_model.replace(
233+
motion_group_model_name=motion_group_desc.motion_group_model.replace(
236234
"_", " "
237235
),
238236
)

exts/wandelbots.omni/wandelbots/omni/instances/models.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import wandelbots_api_client.v2 as wb_v2
77
from wandelbots.omni.utils.api import get_api_client
88
from wandelbots.omni.ui.colors import NOVAColor
9+
from packaging.version import Version
910

1011

1112
class NOVAInstance(BaseModel):
@@ -37,10 +38,21 @@ def status(self) -> str:
3738
def create_api_client(self) -> wb_v2.ApiClient:
3839
raise NotImplementedError("Subclasses must implement the get_api_client method")
3940

41+
@property
42+
def is_compatible(self) -> bool:
43+
if self.version is None:
44+
return False
45+
try:
46+
return Version(self.version).base_version >= Version("25.8.0").base_version
47+
except Exception:
48+
return False
49+
4050
@property
4151
def status_color(self):
4252
if not self.is_reachable:
4353
return NOVAColor.ERROR_MAIN.color
54+
elif not self.is_compatible:
55+
return NOVAColor.WARNING_MAIN.color
4456
elif self.cells:
4557
return NOVAColor.SUCCESS_MAIN.color
4658
else:
@@ -116,7 +128,7 @@ def create_api_client(self) -> wb_v2.ApiClient:
116128

117129
class NOVAMotionGroupData(BaseModel):
118130
name: str
119-
model_name: str
131+
motion_group_model_name: str
120132

121133

122134
class NOVAControllerData(BaseModel):

exts/wandelbots.omni/wandelbots/omni/io/io_stream_service.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ async def _unsubscribe(self, subscription_id: Subscription.Id):
151151

152152
self._remove_subscription(subscription_id)
153153

154-
if stream_running:
154+
if stream_running and len(self.io_subscriptions.keys()) > 0:
155155
await self.start_stream()
156156

157157
def _add_subscription(self, subscription: Subscription, ios: list[str]):
@@ -188,6 +188,7 @@ def _remove_subscription(self, subscription_id: Subscription.Id):
188188

189189
async def _restart_stream(self):
190190
"""Might be used when a subscription changed"""
191+
carb.log_verbose(f"Restarting stream {self.cell}/{self.controller}")
191192
await self.stop_stream()
192193
await self.start_stream()
193194

@@ -219,7 +220,9 @@ async def _receive_io_state(self, io_result_data: str):
219220
async def start_stream(self):
220221
async with self._io_stream_lock:
221222
if len(self.io_subscriptions.keys()) == 0:
222-
carb.log_warn(f"{self.cell}/{self.controller} has no ios")
223+
carb.log_verbose(
224+
f"Trying to start {self.cell}/{self.controller} without ios"
225+
)
223226
return
224227

225228
if self.io_stream and self.io_stream.streaming:

exts/wandelbots.omni/wandelbots/omni/manipulators/motion_group_service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
try:
77
import isaacsim.core.utils.prims as prims_utils
88
except ImportError:
9-
import omni.isaac.core.utils.prims as prims_utils
9+
import omni.isaac.core.utils.prims as prims_utils # type: ignore
1010

1111
carb.log_warn("motion_group_service is using legacy isaac sim imports")
1212
import omni.timeline
@@ -27,7 +27,6 @@ def __init__(self):
2727
self.timeline = omni.timeline.get_timeline_interface()
2828

2929
def has_motion_group(self, prim_path: str) -> bool:
30-
print(f"Host database motion groups: {host_database['motion_groups']}")
3130
return prim_path in host_database["motion_groups"]
3231

3332
def get_all_motion_group_prim_paths(self) -> list[str]:

exts/wandelbots.omni/wandelbots/omni/manipulators/motion_stream_connector.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ async def open(self):
8383
self.api_configuration = self._get_api_configuration(get_auth_token())
8484

8585
result = await self.get_motion_group_state()
86-
self.stream_joint_count = len(result.joint_position.joints)
86+
self.stream_joint_count = len(result.joint_position)
8787
carb.log_info(
8888
f"Start {self.configuration.motion_group} jointCount={self.stream_joint_count} externalJoints={self.is_external_joint_stream}"
8989
)
@@ -207,12 +207,12 @@ async def _parse(self, data: dict):
207207
)
208208

209209
def _update_joints(self, motion_response_result: wb_models.MotionGroupState):
210-
self._last_joints = motion_response_result.joint_position.joints
210+
self._last_joints = motion_response_result.joint_position
211211

212212
if self.timeline.is_stopped():
213213
return
214214

215-
self.apply_joints(motion_response_result.joint_position.joints)
215+
self.apply_joints(motion_response_result.joint_position)
216216

217217
async def _update_joints_in_external_mode(
218218
self, motion_response_result: list[wb_models.ExternalJointStreamDatapoint]

exts/wandelbots.omni/wandelbots/omni/ogn/nodes/OgnOnIOChange.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,19 @@ def set_metadata(self, robot_prim: list[pxr.Sdf.Path], io_id: str):
5151
self.robot_config = self.robot_service.get_motion_group_by_prim_path(
5252
self.robot_prim
5353
)
54-
motion_stream_config = self.robot_config.motion_stream_configuration
5554
if self.robot_config is None:
5655
raise ValueError(
5756
f"No robot configuration found for {self.robot_prim}. Make sure to create a robot for the selected prim"
5857
)
58+
59+
motion_stream_config = self.robot_config.motion_stream_configuration
60+
5961
self.api_configuration = ApiConfiguration(
6062
host=motion_stream_config.host,
6163
secure_connection=motion_stream_config.secure_connection,
6264
access_token=get_auth_token(),
6365
)
66+
6467
self.io_id = io_id
6568
self.io_sub = asyncio.get_event_loop().run_until_complete(
6669
get_io_stream_service().subscribe(
@@ -72,6 +75,11 @@ def set_metadata(self, robot_prim: list[pxr.Sdf.Path], io_id: str):
7275
)
7376
)
7477

78+
def reset(self):
79+
self.io_sub = None
80+
self.robot_prim = None
81+
self.io_id = None
82+
7583

7684
class OgnOnIOChange:
7785
"""
@@ -96,17 +104,17 @@ def release(node):
96104
@staticmethod
97105
def compute(db: OgnOnIOChangeDatabase) -> bool:
98106
"""Compute the outputs from the current input"""
107+
state: OgnOnIOChangeState = db.per_instance_state
99108

100109
if not timeline.is_playing():
110+
state.reset()
101111
return
102112

103113
if len(db.inputs.robot) == 0:
104114
db.log_error("Robot root prim not defined")
105115
return False
106116

107117
try:
108-
state: OgnOnIOChangeState = db.per_instance_state
109-
110118
if db.inputs.robot[0] != state.robot_prim or db.inputs.io_id != state.io_id:
111119
state.set_metadata(db.inputs.robot, db.inputs.io_id)
112120

0 commit comments

Comments
 (0)