# Create a digital twin of a meter [Python]

# Introduction

# About

In this tutorial, you are going to create a digital twin representing a meter. The digital twin will consist of a Twin, a Ledger, and Identities.

  • You are going to set up your environment and create a free Trusted Twin account. With the User Secret (API key) provided upon creation of the account, you are going to create a new role, a new user and a new User Secret (API key) that you will use in this tutorial.
  • You are going to create the objects of the digital twin of the meter one by one.
  • You are going to combine these steps to a convenient method to create a digital twin of a meter.
  • You are going to learn how to store and read measurements, retrieve measurement history, and change meter location. In case you don't have real meters that can provide measurements, we prepared test data based on open weather data from Gdańsk in Poland.
  • You are going to use the reference feature to connect meters.

# Resources


This tutorial is available as a standalone Jupyter notebook. You can find it in the Trusted Twin public repository in the Trusted Twin Tutorial Resources(opens new window) section.

# Requirements

This tutorial requires:

# Install the Trusted Twin library

As first step, install the Trusted Twin Python library using the pip package manager for Python.

# Set up your environment

Next, set up your environment.

# Get a Super Admin User Secret

On the Trusted Twin platform User authentication is based on User Secrets (API keys).

In order to obtain a Super Admin User Secret (API key):

  1. Go to the Trusted Twin Self-care panel(opens new window) and follow the instructions to create an account.
  2. Once you have created an account, a Super Admin User Secret (API key) for the Super Admin user of the account you created will be displayed.


The User Secret (API key) is displayed only once. It is not stored in the Trusted Twin system, and it cannot be retrieved. Keep your User Secret stored in a secure place. If you lose your User Secret, the User Secret generation process will need to be started from the beginning.

# Authenticate requests

Once you have your Super Admin User Secret, you can use it to authenticate requests.

# Get account, user and role

Method Path Operation
GET /whoami who_am_i
GET /roles/{role} get_user-role

When you create a Super Admin User Secret, a Super Admin Role and a Super Admin role are created automatically. Let's retrieve the UUIDs the account, user, and role that the Super Admin User Secret is associated with as well as the details of the Super Admin Role.

The response to the who_am_i endpoint returns information associated with the User Secret (API key) - the account UUID, the user UUID, and the role UUID.

The get_user_role response returns the name of the role, information about the user's access to resources (Twins and Ledger Entries, in addition to the ones belonging to the account where the role was created), and a role statement defining the actions a user can perform on the resources.


A Super Admin Role allows the user to perform all actions available on the Trusted Twin platform. Also, when new actions related to new features are introduced, they are added by default to the Super Admin role.
We highly recommend that you create roles for users with permissions that allow them to only perform actions required for their position in the organisation and on resources that they need access to.

As next steps we are going to create a new role, user and generate a User Secret (API key) for this user. Once we have generated it, we are going to authenticate with this User Secret (API key) for the operations that we are going to perform in this tutorial.

# Create a role

Let's create a role to perform operations on the Trusted Twin platform.

A role is a collection of permissions:

  • you can "allow" or "deny" "actions" that correspond with endpoint operations,
  • you can grant permission to resources - specific "twin", "identity" or "ledger" objects.
Method Path Operation
POST /roles create_user_role

You are going to create a role with permissions to perform actions required for this tutorial (see "actions" in the request body below) and allow operations only on Twins that have an "application" field in the "description" where the value is set to "Trusted Twin DEMO App" ("twin": "TWIN.application == 'Trusted Twin DEMO App'"). Please note that the "create", "update", and "delete" actions related to operations on roles, users, and User Secrets should not be included in the list of "actions". It is because the role you are going to create should not be used for user management purposes.

# Create a user

After creating a role, let's create a user with the above role.

A user is a person who utilizes the Trusted Twin platform. The permissions of a user to access, create, and manipulate Trusted Twin resources are controlled by the role assigned to the user.

Method Path Operation
POST /users create_user

# Create a User Secret PIN

Method Path Operation
POST /users/{user}/secrets create_user_secret_pin

A user needs a User Secret (API key) to authenticate on the Trusted Twin platform.

Let's create a User Secret PIN. It will be required to create a User Secret (API key) in the next step. The User Secret PIN can be passed to a third party so that they can create a User Secret for themselves.


A User Secret PIN is valid for 10 minutes, and it can be used only once to generate a User Secret (API key). After a User Secret (API key) has been generated, the User Secret PIN automatically expires.

# Create a User Secret (API key)

Method Path Operation
POST /secrets/{account}/{pin} create_user_secret

Once you have created a User Secret PIN, you can use it to generate a User Secret.


Please note that the User Secret is displayed only once. It is not stored in the Trusted Twin system, and it cannot be retrieved. Keep your User Secret stored in a secure place. If you lose your User Secret, you will need to start the User Secret generation process from the beginning.

The result is a User Secret (API key) that we will use throughout this tutorial. We are going to use it to authenticate requests.

# Digital twin

# Create a Twin

Method Path Operation
POST /twins create_twin

You are going to create a digital twin that will represent a water meter. The digital twin will consist of a Twin, a Ledger and Identities. First, you are going to create a Twin of a meter. A Twin is an object on the Trusted Twin platform that ties together all knowledge in the Digital Twin.

A Twin can have an optional description field. A description of a Twin is always publicly accessible. This means that anyone who knows the unique identifier (UUID) of the Twin will be able to view the description of the Twin. The Twin you are going to create will have a description field with information about the application name, object type, serial number, and website.

Please note that the description below contains a placeholder (ADD_YOUR_METER_SERIAL_HERE). You need to add a serial number for the meter in place of the placeholder. You can insert any serial number that works for you. In our example, the "serial" is "12345".

As you can see in the response, you are the "owner" and "creator" of the Twin. The owner of a Twin can change the description of the Twin by sending a request to the update_twin endpoint if the status of the Twin is "alive".

# Add Ledger Entries

Let's add Entries to the Twin's Ledger. A Ledger is an object that stores information about the state of a Twin. A Ledger contains Entries that are user-defined key-value pairs.

Method Path Operation
POST /twins/{twin}/ledgers/personal add_twin_ledger_entry

The Entries of your Ledger are going to contain the following information about the state of the Twin:

  • current meter reading ("reading" Entry),
  • battery level ("battery" Entry),
  • log of errors raised through the meter software ("log" Entry),
  • location of where the water meter is installed ("location" Entry).

Please note that in the above "reading" Entry, we used the "visibility" and "history" attributes:

  • The "visibility" attribute defines the visibility of the data in the Entry for other accounts.
  • The "history" attribute defines the time period for which the history of value changes is stored (in our case it is set to 1 month). The History service lets you store historical values of an Entry of a Ledger.
    You will use these fields later on in this tutorial.

You can execute the above code multiple times to observe the API response for when a given Entry has been already added to the Ledger.

# Create an Identity

Let's create an Identity to identify the meter. Although Twins have system-defined unique IDs (UUIDs), you might need to use user-generated IDs specific to your business to identify Twin. You can use Identities for this purpose.

Method Path Operation
POST /twins/{twin}/identities create_twin_identity

The Identity that you are going to create is going to be a combination of the unique identifier of the account (account UUID) and the serial number of the meter.

The "visibility" attribute is set to null. It means that the Identity is private and not visible to other accounts. The "validity_ts" is set to null. It means that the Identity does not expire.

Your first digital twin representing a meter is ready!

# Digital twin

Let's connect all the above steps into a convenient create_meter() method that handles all the above operations and create a digital twin.

# Store and read measurements, retrieve history, change location

Below you will find methods that let you:

  • store meter measurements: store_measurement(),
  • read current meter measurements: read_measurement(),
  • read the history of meter measurements: read_history(),
  • store the location of the meter: set_location().

Each time a new meter reading is available, your meter can call the store_measurement() method. Your application can read that measurement by calling the read_measurement() method.

Method Path Operation
GET /resolve/{identity} resolve_twin_identity
PATCH /twins/{twin}/ledgers/personal update_twin_ledger_entry
GET /twins/{twin}/ledgers/personal get_twin_ledger_entry
GET /twins/{twin}/ledgers/personal/history get_twin_ledger_entry_history

In the previous section of this tutorial, the "reading" Entry was configured to store "history" of changes. This way, the historical meter readings will be stored for the time period defined in the "history" attribute. You can call the read_history() method to read the history of these changes.

You will notice that each time you call a method, the Identity of the meter is resolved to a Twin UUID (resolve_twin_identity endpoint). This can easily be cached as the meter serial number is not going to change.

Let's test the flow of the measurement data!


The Trusted Twin platform also offers advanced services to store and handle historical data and state of objects - Timeseries and Indexes.

# Use open weather data

# About

In case you don't have real meters that can provide measurements for your test, we prepared test data for you based on open weather data from Gdańsk in Poland.

We created one digital twin of all the weather stations that provides information about temperature on an hourly basis. The Ledger was created by us, so it is owned the account with the below account UUID.

Please note that you can access data stored in the Ledger Entries, although you belong to a different account.

Entries in a Ledger are visible by default to all users belonging to that account. However, you can set up the "visibility" of an Entry so that it is also visible to users belonging to other accounts (foreign accounts). To make it possible, the visibility rule needs to resolve to true for a user of a foreign account. If you set the "visibility": "true", the Entry will be visible to users belonging to foreign accounts.

In the Ledger below, the Entry "meters" is a list of all available weather stations with their real IDs (e.g., 307) and serial numbers attached to them (e.g., sn_0000000). All other Entries are temperature readings. All Entries have visibility rules set to "true". This means that the Entries are visible to everyone as the rule in each of the Entries always resolves to true.

# Using public Identity

We have also created a public Identity that is visible for everyone (visibility rule is set to "true").

# Resolve public Identity and read measurements

To find out the UUID of the weather data Twin, you need to resolve the Identity. You have to set a context in which the Identity should be resolved (the account _TT_DEMO_ACCOUNT), because you are not the owner of that Identity.

Method Path Operation
GET /resolve/{identity} resolve_twin_identity
GET /twins/{twin}/ledgers/{ledger}/value get_twin_ledger_entry_value

There should be only one Twin UUID on the list after resolving the Identity.

Let's store the Twin UUID as _TT_DEMO_DATA_TWIN for future use.

You can also check a single measurements with the timestamp of the last update of the measurement.

# Use references to connect meters

# About

The Trusted Twin platform offers a functionality allowing you to reference any visible Entry from a different Ledger. This Ledger could be your own Ledger attached to a different Twin, or any Ledger owned by a different account.

Reference structure: twin://{twin_uuid}/{account_uuid}/{entry_name}
Reference example: twin://e5dc9775-2aed-4eb6-9f4c-56960b8858f2/574a9445-267d-4d4d-946d-9313b137fcd8/sn_0000000.

Let's create a reference to demo meters. We are going to reference an Entry in the Twin _TT_DEMO_DATA_TWIN and _TT_DEMO_ACCOUNT. The Entry is equal to the ID of the meter (meter_id, in our example above it is "sn_0000000").

Method Path Operation
GET /resolve/{identity} resolve_twin_identity
DELETE /twins/{twin}/ledgers/personal delete_twin_ledger_entry
ADD /twins/{twin}/ledgers/personal add_twin_ledger_entry

As you can see, the source is pointing to the right value.

# Read measurements after update

Our next call to the read_measurement() method will show that the value was initiated as expected.

Method Path Operation
GET /resolve/{identity} resolve_twin_identity
GET /twins/{twin}/ledgers/personal get_twin_ledger_entry