Search & Describe Twins

Find your own and others' Digital Twins by using the Search Twin function. Understand and inspect their data by using Describe or List All Twins.

This page covers:


Introduction to Search Twins

Use the Search Twin call to find your and others' Digital Twins in your IOTICS ecosystem. You can select and combine one or more search criteria, including:

  • Property: define a list of properties, such as Type, Color, Last Update, etc.;
  • Location: define Latitude, Longitude and a Radius expressed in Km;
  • Text: define one or more keywords that must match text fields from Twin properties.
  • Scope (ownership): distinguish between finding only your own local Digital Twins, vs all global Digital Twins

🚧

Distinguish between your own local Digital Twins and others' remote Digital Twins

  • Local: returns all Digital Twins in your own IOTICSpace
  • Global: returns all Digital Twins in your own and others' (remote) IOTICSpaces.

Please note that you will only find Digital Twins that you have permission to find. See Selective Data Sharing for more information on access permissions.

The following table provides an indication of the filters that can be used in the request parameters when searching for Twins.

Key

Description

Properties

Search by any available Digital Twin property as described here.

Location

Defines a specific geo-location with radius.

Text

Search one or more keywords which must match the text from the Twin's properties. Note that any (rather than all) of the keywords will produce a match.

Scope

Distinguish between Twins in your own local Host/IOTICSpace or all Twins in your global network.

Limit

Define the maximum number of Twins to return.

Offset

Used to return results from a given offset.

An important feature of the Search function is that it allows to search and describe one or more Twins with one single call through the responseType body parameter. It can be set to:

  • MINIMAL: used to return minimal responses including a Twin's DID and visibility setting;
  • LOCATED: includes the MINIMAL fields in addition to the Twin's location;
  • FULL (default): provides a complete description of the Twin, including all metadata about the Twin, its Feeds and the Feeds' Values.

How to search for Twins 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);
import json
from datetime import datetime, timedelta, timezone
from requests import request

twins_list = []  # Initialise an empty list. It will contain the list of Twins retrieved by the search

# Add a new field in the headers.
# Client request timeout is used to stop the request processing once the timeout is reached
headers.update(
    {
        "Iotics-RequestTimeout": (
            datetime.now(tz=timezone.utc) + timedelta(seconds=10)
        ).isoformat(),
    }
)

with request(
    method="POST",
    url=f"{HOST}/qapi/searches",  # Replace with URL of the Host
    headers=headers,  # It includes the token and the Request Timeout
    stream=True,
    verify=False,
    params={"scope": "LOCAL"},
    json={
        "filter": {
            "properties": [
                {
                    "key": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
                    "uriValue": {"value": "http://data.iotics.com/app#Model"},
                }
            ],
            "text": "temperature",
            "location": {
                "location": {"lon": 52.2, "lat": 0.119},
                "radiusKm": 3.2,
            }
        }
    }
) as resp:
    # Raises HTTPError, if one occurred
    resp.raise_for_status()
    # Iterates over the response data, one line at a time
    for chunk in resp.iter_lines():
        response = json.loads(chunk)
        twins_found = []
        try:
            twins_found = response["result"]["payload"]["twins"]
            host_id = response["result"]["payload"]["remoteHostId"]["value"]
        except KeyError:
            host_id = "local"
        finally:
            if twins_found:
                # Append the twins found to the list of twins
                twins_list.extend(twins_found)

print(f"Found {len(twins_list)} twin(s)")

Introduction to Describe Twins

Use Describe Twin to inspect a Digital Twin's metadata and find out more about it. It returns information about the Twin itself, its Feeds and each of the Feeds' Values in order to allow you to distinguish one Twin from another.

🚧

A prerequisite for Describe Twin is the Twin's DID

You may know it already or have to retrieve it by using Search Twin.

How to describe a Twin with the IOTICS API

🚧

Local vs Remote

The Describe Twin API is used differently depending on whether the Twin is in your own local IOTICSpace or in another remote IOTICSpace.

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);
from requests import request

response = request(
    method="GET",
    url=f"{HOST}/qapi/twins/{twin_id}",  # Replace with URL of the Host and the Twin DID you want to describe
    headers=headers,  # It includes the token
)

response.raise_for_status()
print(response.json())
from requests import request

response = request(
    method="GET",
    # Replace the 'url' with:
    # - URL of your Host
    # - the ID of the Host where that Twin belongs
    # - the Twin DID you want to describe
    url=f"{HOST}/qapi/hosts/{host_id}/twins/{twin_id}",
    headers=headers,  # It includes the token
)

response.raise_for_status()
print(response.json())

Introduction to List All Twins

List All Twins allows you to list and describe all Digital Twins of a specific IOTICSpace.

🚧

Please note that you will only be able to list Digital Twins that you have permission to find. See Selective Data Sharing for more information on access permissions.

How to list all Twins 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);
from requests import request

response = request(
    method="GET",
    url=f"{HOST}/qapi/twins",  # The host where to retrieve all the Twins
    headers=headers,  # It includes the token
)

response.raise_for_status()
print(response.json())

Tutorial of the Search & Describe section

Click here to see the entire code on how to search and describe a Twin

import json
from datetime import datetime, timedelta, timezone

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 = None):
    response = request(method=method, url=url, headers=headers, json=json)
    response.raise_for_status()

    return response.json()


def describe_remote_twin(host_id: str, twin_id: str):
    remote_twin = make_api_call(
        method="GET", url=f"{HOST}/qapi/hosts/{host_id}/twins/{twin_id}"
    )

    return remote_twin


# Not used in this example
def describe_local_twin(twin_id: str):
    local_twin = make_api_call(method="GET", url=f"{HOST}/qapi/twins/{twin_id}")

    return local_twin


# Set up the API with authentication delegation so the AGENT can authenticate on behalf of the USER
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",
}

# Initialise an empty list.
# It will contain the list of Twins retrieved by the search
twins_list = []

# Add a new field in the headers.
# Client request timeout is used to stop the request processing once the timeout is reached
headers.update(
    {
        "Iotics-RequestTimeout": (
            datetime.now(tz=timezone.utc) + timedelta(seconds=10)
        ).isoformat(),
    }
)

with request(
    method="POST",
    url=f"{HOST}/qapi/searches",  # Replace with URL of the Host
    headers=headers,  # It includes the token and the Request Timeout
    stream=True,
    verify=False,
    params={"scope": "GLOBAL"},
    json={"responseType": "MINIMAL", "filter": {"text": "cambridge"}},
) as resp:
    # Raises HTTPError, if one occurred
    resp.raise_for_status()
    # Iterates over the response data, one line at a time
    for chunk in resp.iter_lines():
        response = json.loads(chunk)
        twins_found = []
        try:
            twins_found = response["result"]["payload"]["twins"]
            host_id = response["result"]["payload"]["remoteHostId"]["value"]
        except KeyError:
            host_id = "local"
        finally:
            if twins_found:
                # Add the host id value to each twin
                for twin in twins_found:
                    twin["hostId"] = host_id

                # Append the twins found to the list of twins
                twins_list.extend(twins_found)

print(f"Found {len(twins_list)} twin(s)")

twin_of_interest = next(
    iter(twins_list)
)  # For demo purpose take the fist Twin in the list
twin_id = twin_of_interest["id"]["value"]
twin_host_id = twin_of_interest["hostId"]

headers.pop("Iotics-RequestTimeout")  # RequestTimeout no longer needed in the headers

remote_twin = describe_remote_twin(host_id=twin_host_id, twin_id=twin_id)
print(remote_twin)

Did this page help you?