Update Twins

This page covers how to set a Digital Twin's metadata properties as well as the data feeds' properties and each of their values. Settings such as a Digital Twin's Location, Visibility and Accessibility can be updated using this function.

🚧

The Update Twin function can only be performed against an existing Digital Twin. If you'd like to combine Create and Update in a single call, you can use the Upsert Twin function instead.


Introduction to Update Digital Twins

There are different types of updates that can be performed against a Digital Twin:

  1. Add or update metadata of an existing Digital Twin
    • this includes special settings such as Location, Visibility and Accessibility
    • how to distinguish a generic Digital Twin from a Digital Twin Model, and
    • special settings to visualise and categorise a Digital Twin on the IOTICS user interface
  2. Add or update metadata of an existing Digital Twin's data feed
    • set each data feed's metadata and settings, and
    • specify each of the data feed's values

Add or update metadata of an existing Digital Twin

Adding and updating a Digital Twin's metadata properties is typically done by using the Update Digital Twin function. The tables below describes the most common properties, however any custom property can be added and there is no limit on the quantity of properties per twin.

Special metadata properties

Please note that some properties like Location and Visibility are special settings that have to be treated differently. The more generic or custom properties will be listed in the List of Properties.

Property

Description

Example

Location

Latitude and Longitude of the Digital Twin. It serves to correctly locate the Digital Twin on the IOTICSpace user interface map.

Digital Twins without a Location property won't show on the map. They still exist though and can be found, accessed and interoperated

{"lat": 51.5, "lon": -0.1}

Visibility

Defines the Visibility of a Digital Twin: whether its metadata is visible or not to another IOTICSpace

"PRIVATE" / "PUBLIC"

Properties

List of other Properties to add to the Twin. Every property needs to be defined according to a pre-existing ontology in a predicate-object fashion (see table below).

"langLiteralValue": {"value": "Temperature Sensor", "lang": "en"}}]```

Generic metadata properties

The generic properties described in the table below make use of an existing Ontology and should be added to the Digital Twin's list of properties. Any custom property can be created and there is no limit to the number of properties per Digital Twin.

Please note that some properties are mandatory, some are best practice and some are required in order for the Twin to be visualised and categorised in the IOTICSpace user interface.

Property

Description

Example

Label

A short description of the Digital Twin. Corresponds to "Name" in the IOTICSpace interface.

Not mandatory but best practice.

"langLiteralValue": {"value": "Temperature Sensor", "lang": "en"}```

Comment

An explanatory description of the Digital Twin. Corresponds to "Description" in the IOTICSpace interface.

Not mandatory but best practice.

"langLiteralValue": {
    "value": "A temperature sensor that shares temperature data",
    "lang": "en",
}```

Type

Used to define the specific type of the Twin such as HostTwin, Model or any other type defined by an existing Ontology.

Mandatory for Digital Twin Models.

"uriValue": {"value": "https://data.iotics.com/app#Model"}```

Created From

States whether the Digital Twin has been created from a Digital Twin Model, or not.

Mandatory for "generic" Digital Twins.

"uriValue": {
    "value": "https://data.iotics.com/app#ByModel"
}```

From Model

References the DID of the Digital Twin Model they have been created from.

Mandatory for "generic" Digital Twins.

"uriValue": {"value": model_twin_did}```

Colour

Defines the colour of the Twins to be shown in the User Interface.

Not mandatory but best practice.

"stringLiteralValue": {"value": "#d6df23"}```

IOTICSpace name

Defines the specific IOTICSpace name where the Twin belongs to.

Not mandatory but best practice.

"stringLiteralValue": {"value": "uk-metoffice"}```

Created At

Defines the timestamp at which the Twin was created.

"literalValue": {"dataType": "dateTime", "value": datetime_twin_creation_string}```

Updated At

Defines the timestamp at which the Twin was last updated.

"literalValue": {"dataType": "dateTime", "value": datetime_twin_update_string}```

AllowList

Defines the Accessibility of the Twin: whether the Digital Twin's data can be accessed (or not) by a Digital Twin from another IOTICSpace

"uriValue": {"value": "http://data.iotics.com/public#allHosts"}```

How to update metadata properties of an existing Digital Twin with the IOTICS API

Click to see the prerequisites

  1. Create your user credentials (guide);
  2. Delegate the agent so it can work on behalf of the user (guide);
  3. Create your token to interact with your Host (guide);
  4. Create headers to be added alongside the API request (guide);
1. Create Twin with control delegation and get a new "twin_registered_id"
2. Use the Create Twin API call
3. Use the Update Twin API call
from requests import request

response = request(
    method="PATCH",
    url=f"{HOST}/qapi/twins/{twin_did}",  # Replace with URL of the Host and the ID of the Twin to update
    headers=headers,  # It includes the token
    json={
        "location": {"location": {"lat": 6.1, "lon": 1.4}},
        "newVisibility": {"visibility": "PRIVATE"},
        "properties": {
            "added": [
                # Add a Label
                {
                    "key": "http://www.w3.org/2000/01/rdf-schema#label",
                    "langLiteralValue": {"value": "Temperature Sensor", "lang": "en"},
                },
                # Add a comment
                {
                    "key": "http://www.w3.org/2000/01/rdf-schema#comment",
                    "langLiteralValue": {
                        "value": "A temperature sensor that shares temperature data",
                        "lang": "en",
                    },
                },
            ]
        },
    },
)

response.raise_for_status()

Add or update metadata of an existing Digital Twin's data feed

A Digital Twin can have none, one or more data feeds. Each data feed is distinct, with its own identity, settings and list of properties (values).

Data feed metadata

Each data feed has to be described separately. The following table provides an indication on what the data feed's metadata can include.

Property

Description

Example

storeLast

Defines whether or not the feed should store the latest shared value.

"True" / "False"

Values metadata

Defines the metadata of the data feed's Values (see table below).

"comment": "Temperature in degrees Celsius",
"dataType": "decimal",
"label": "value",
"unit": "http://purl.obolibrary.org/obo/UO_0000027",
}]```

Properties

List of Properties to add to the Twin's Feed. Similar to the Twin's Properties, every feed's property needs to be defined according to a pre-existing ontology in a predicate-object fashion.

"langLiteralValue": {"value": "Current Temperature", "lang": "en"}}]```

Data field (Value) metadata

Each data field (or Value) of each data feed also needs to be described with metadata properties.

The following table provides an indication on what the data field's metadata can include.

Property

Description

Example

Comment

An explanatory description of the Value. Corresponds to "Field Description" in the IOTICSpace user interface.

Best practice

"Temperature in degrees Celsius"

Data Type

Defines the xsd type in shorthand notation. Corresponds to "Type" in the IOTICSpace user interface.

Mandatory

"decimal"

Label

A short description of the Value. Corresponds to "Field Name" in the IOTICSpace user interface.

Mandatory

"reading"

Unit

The unit of measure of the Value's content. This field needs to be passed as a URI to a pre-existing Ontology.

Optional

"http://purl.obolibrary.org/obo/UO_0000027"

How to update an existing data feed with the IOTICS API

Click to see the prerequisites

  1. Create your user credentials (guide);
  2. Delegate the agent so it can work on behalf of the user (guide);
  3. Create your token to interact with your Host (guide);
  4. Create headers to be added alongside the API request (guide);
1. Create Twin with control delegation and get a new "twin_registered_id"
2. Use the Create Twin API call
3. Use the Create Feed API call
4. Use the Update Feed API call
from requests import request

response = request(
    method="PATCH",
    url=f"{HOST}/qapi/twins/{twin_id}/feeds/{feed_id}",  # Replace with URL of the Host, the ID of the Twin owning the Feed and the ID of the Feed
    headers=headers,  # It includes the token
    json={
        "storeLast": True,
        "properties": {
            "added": [
                # Add a Label
                {
                    "key": "http://www.w3.org/2000/01/rdf-schema#label",
                    "langLiteralValue": {"value": "Current Temperature", "lang": "en"},
                },
                # Add a Comment
                {
                    "key": "http://www.w3.org/2000/01/rdf-schema#comment",
                    "langLiteralValue": {
                        "value": "The current temperature reading",
                        "lang": "en",
                    },
                },
            ]
        },
        "values": {
            "added": [
                {
                    "comment": "Temperature in degrees Celsius",
                    "dataType": "decimal",
                    "label": "reading",
                    "unit": "http://purl.obolibrary.org/obo/UO_0000027",
                }
            ]
        },
    },
)

response.raise_for_status()

Tutorial of the Update Twin section

Click to see the entire code on how to update a Twin and a Feed

from typing import List

from iotics.lib.identity.api.high_level_api import get_rest_high_level_identity_api
from requests import request

RESOLVER_URL = "resolver_url"
HOST = "host_url"

USER_KEY_NAME = "user_key_name"
AGENT_KEY_NAME = "agent_key_name"
USER_SEED = bytes.fromhex("user_seed")
AGENT_SEED = bytes.fromhex("agent_seed")


def make_api_call(method: str, url: str, json: dict):
    response = request(method=method, url=url, headers=headers, json=json)
    response.raise_for_status()

    return response.json()


def create_twin(twin_key_name: str):
    twin_registered_id = api.create_twin_with_control_delegation(
        twin_seed=AGENT_SEED,
        twin_key_name=twin_key_name,
        agent_registered_identity=agent_registered_id,
        delegation_name="#ControlDeleg",
    )

    make_api_call(
        method="POST",
        url=f"{HOST}/qapi/twins",
        json={"twinId": {"value": twin_registered_id.did}},
    )

    return twin_registered_id.did


def create_feed(twin_id: str, feed_id: str):
    make_api_call(
        method="POST",
        url=f"{HOST}/qapi/twins/{twin_id}/feeds",
        json={"feedId": {"value": feed_id}},
    )


def update_twin_with_metadata(
    twin_id: str,
    properties: List[dict] = None,
    location: dict = None,
    visibility: str = "PRIVATE",
):
    payload = {"newVisibility": {"visibility": visibility}}

    if location:
        payload["location"] = location

    if properties:
        payload["properties"] = {"added": properties}

    make_api_call(method="PATCH", url=f"{HOST}/qapi/twins/{twin_id}", json=payload)


def update_feed(
    twin_id: str,
    feed_id: str,
    properties: List[dict] = None,
    values_metadata: List[dict] = None,
    store_last=True,
):
    payload = {"storeLast": store_last}

    if properties:
        payload["properties"] = {"added": properties}

    if values_metadata:
        payload["values"] = {"added": values_metadata}

    make_api_call(
        method="PATCH", url=f"{HOST}/qapi/twins/{twin_id}/feeds/{feed_id}", json=payload
    )


api = get_rest_high_level_identity_api(resolver_url=RESOLVER_URL)
(
    user_registered_id,
    agent_registered_id,
) = api.create_user_and_agent_with_auth_delegation(
    user_seed=USER_SEED,
    user_key_name=USER_KEY_NAME,
    agent_seed=AGENT_SEED,
    agent_key_name=AGENT_KEY_NAME,
    delegation_name="#AuthDeleg",
)

token = api.create_agent_auth_token(
    agent_registered_identity=agent_registered_id,
    user_did=user_registered_id.did,
    duration=600,
)

headers = {
    "accept": "application/json",
    "Iotics-ClientAppId": "example_code",
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json",
}

twin_did = create_twin(twin_key_name="SensorTwin")

print(f"Twin {twin_did} created succesfully")

# Add metadata to the Twin
update_twin_with_metadata(
    twin_id=twin_did,
    properties=[
        # Add a Label
        {
            "key": "http://www.w3.org/2000/01/rdf-schema#label",
            "langLiteralValue": {"value": "Temperature Sensor", "lang": "en"},
        },
        # Add a comment
        {
            "key": "http://www.w3.org/2000/01/rdf-schema#comment",
            "langLiteralValue": {
                "value": "A temperature sensor that shares temperature data",
                "lang": "en",
            },
        },
    ],
    # Add location coordinates
    location={"location": {"lat": 51.5, "lon": -0.1}},
)

print("Twin updated with metadata")

feed_id = "currentTemp"
create_feed(twin_id=twin_did, feed_id=feed_id)

print(f"Feed {feed_id} created succesfully")

# Add Feed's Metadata and a Value's Metadata
update_feed(
    twin_id=twin_did,
    feed_id=feed_id,
    properties=[
        # Add a Label
        {
            "key": "http://www.w3.org/2000/01/rdf-schema#label",
            "langLiteralValue": {"value": "Current Temperature", "lang": "en"},
        },
        # Add a comment
        {
            "key": "http://www.w3.org/2000/01/rdf-schema#comment",
            "langLiteralValue": {
                "value": "The current temperature reading",
                "lang": "en",
            },
        },
    ],
    # Add Value's metadata
    values_metadata=[
        {
            "comment": "Temperature in degrees Celsius",
            "dataType": "decimal",
            "label": "reading",
            "unit": "http://purl.obolibrary.org/obo/UO_0000027",
        }
    ],
)

print("Feed updated with metadata and Value's metadata")

Did this page help you?