Subscribe to Setting Changes

The omni.kit.app extension contains the SettingChangeSubscription class that allows you to subscribe a callback for when a setting value changes. This is useful for when you want to allow other parts of the app to interactively change the behavior of your extension or to allow them to monitor changes your extension makes to its own settings. This snippet shows how to subscribe to settings value changes and provide a callback function to execute code whenever a setting changes.

Note

Each extension puts settings in /ext/[ext_name]/ to not conflict with settings from other extensions. Extensions should also list their settings in their extension.toml to make the settings discoverable to users and developers.

import carb.settings
import omni.kit.app
import carb.dictionary  # only needed to access item values' types and more advanced manipulations.


def on_change(value: carb.dictionary.Item, change_type: carb.settings.ChangeEventType) -> None:
    """Settings change callback function.  This is called any time a setting with a change subscription
       is created or modified.  This callback implementation demonstrates various ways that the data
       in the changed dictionary item can be accessed.

       Parameters:
           value:       A dictionary item containing the value being watched for changes.  This will
                        be a `carb.dictionary.item` type value and can use all of the access methods
                        available to that type.
           change_type: An enum value indicating the type of change the has occurred.  This will be
                        one of `ChangeEventType.CREATED`, `ChangeEventType.CHANGED`, or
                        `ChangeEventType.DESTROYED`.

       Returns:
           No return value.
       """

    # Access the new value directly from the item object.  This will use the item's magic `__str__()`
    # method to retrieve the value as a string.  Outside of a print() call, this can also be invoked
    # directly with `str(value)`.
    print(value, change_type)
    print(f"value = '{value}', change_type = '{change_type}'.")
    print("value = '" + str(value) + "', change_type = '" + str(change_type) + "'.")


    # Access the value using the `get()` method.  This accepts a path to the sub-item to retrieve the
    # value for and a default value in case the requested sub-item path is not valid.  To retrieve the
    # value stored directly in the given item, just use an empty string for the path.
    if value.get("", "not-fall") == "fall":
        print("The value was changed to 'fall'.")


    # Access the value using the magic `__getitem__()` method.  This allows the item to be treated like
    # a list, array, or table.  To access the value directly in the given item, use an empty string for
    # the index.  To access the value of a sub-item, use the relative path to that sub-item as the index.
    if value[""] == 89:
        print("The value was changed to 89.")


    # Access the value through the `carb.dictionary` interface based on the item's type.  The item's
    # type is retrieved with `get_item_type()`.  The value can then be retrieved using various `get_as_*()`
    # methods based on the returned type.
    dict = carb.dictionary.acquire_dictionary_interface()

    item_type = dict.get_item_type(value)

    if item_type == carb.dictionary.ItemType.BOOL:
        print(f"New boolean value is '{dict.get_as_bool(value)}'.")

    elif item_type == carb.dictionary.ItemType.INT:
        print(f"New integer value is '{dict.get_as_int(value)}'.")

    elif item_type == carb.dictionary.ItemType.FLOAT:
        print(f"New float value is '{dict.get_as_float(value)}'.")

    elif item_type == carb.dictionary.ItemType.STRING:
        print(f"New string value is '{dict.get_as_string(value)}'.")

    elif item_type == carb.dictionary.ItemType.DICTIONARY:
        print("Dictionary value.")


# ****** subscribe to receive change notifications ******
# subscribe to value changes, returned object is subscription holder. To unsubscribe - destroy it.
subscription1 = omni.kit.app.SettingChangeSubscription("/exts/your.ext.name/test/test/value", on_change)


# ****** create and change the watched setting ******
# get the settings interface so we can modify the settings registry.
settings = carb.settings.get_settings()

# create the new setting and set its value to the integer 23.
settings.set("/exts/your.ext.name/test/test/value", 23)

# change the existing integer setting to the string 'fall'.
settings.set("/exts/your.ext.name/test/test/value", "fall")

# change the existing setting to an empty object.  Note that this will not trigger the change callback
# and that id does not delete the existing setting.
settings.set("/exts/your.ext.name/test/test/value", None)

# change the existing string setting to the integer 89.
settings.set("/exts/your.ext.name/test/test/value", 89)


# ****** clean up ******
# release the subscription reference object to stop receiving callbacks.
subscription1 = None

# note that no more notifications are received with this change.
settings.set("/exts/your.ext.name/test/test/value", 100)