The Synchronized Digital Twin (SDT) module aims at being the link between Thing'in platform and IOT platforms to create the complete vision of a Digital Twin: “A digital twin is a virtual representation of real-world entities and processes, synchronized at a specified frequency and fidelity (Digital Twin consortium).”
The SDT module is based on python implementation of actor model named Pykka. An actor is instanciated for each DP to synchronize
The SDT module is only accessible through Thing'in API, thus the global access control, as well as the ACLs of the avatars can be used to restrict the access to the SDT data.
In API endpoints, the uuid used is the uuid of the Thing'in avatar. A SDT also have another uuid in the SDT module, this uuid is stored in the Thing'in avatar under the property DT:uuid
but you won't need to use it directly.
When we associate a SDT to an avatar, we add several fields to the avatar: a label SynchronizedDigitalTwin
and other data properties (DT:uuid
, DT:type
, DT:description
)
Avatar linked to a SDT should be deleted with this endpoint (not /avatar). Or at least the SDT must be removed with this endpoint before deleting the avatar. If the avatar is deleted via /avatar endpoint, the associated SDT should be automatically deleted, but there may be some side effects
Here is an example of the synchro description
{
"iot_attributes": [
{
"name": "x",
"value": "$[?value.addr='3ef8'].value.position[0]"
},
{
"name": "y",
"value": "$[?value.addr='3ef8'].value.position[1]"
},
{
"name": "z",
"value": "$[?value.addr='3ef8'].value.position[2]"
}
],
"thingin_attributes": [
{
"name": "DT:data",
"value": "{{\"coordX\":{x},\"coordY\":{y},\"coordZ\":{z}}}",
"value_template": "python",
"frequency_sec": 30
}
]
}
The first part, iot_attributes, allow you to retreive part of the raw data (thanks to a jsonpath expression - see jsonpath-ng) and store it to a variable
The second part, thingin_attribute, allow you to build a DP on the Thing'in avatar, using the variable defined in the previous section.
Several syntaxes are available to use variable (set in value_template
):
direct
: if the DP must be updated with a variable defined in iot_attributes without any transformation, use this template and specify only the variable name under value
python
(default): is the one for python format function: each variable must be surronded by {}
(and you must escape {
and }
characters by doubling them)mustache
: use mustache templating (https://mustache.github.io/). The result is interpreted as a string.json_mustache
: use mustache templating (https://mustache.github.io/). The result is interpreted as a json object.You must also define a synchronisation frequency (0 means no synchro). The module will poll the IOT platform at the defined frequency and update the thing'in avatar.
Updates done on an avatar that is synchronized can be replicated/sent to its IoT platform, thus realizing bi-directionnal updates, from the platform to Thing'in and vice-versa. To implement this, the synchronization object can be extended with the command_value
field, which will hold the payload to send to the IoT platform with the updated value of the corresponding property.
Below is an example of such synchronization to update properties of a light bulb : this device synchronizes 3 properties on
, bri
and sat
, which are previously defined as Labels in Thing'in. To extract data from the platform, a json-path
extracts the appropriate values (see previous section). To push updates from Thing'In to the platform, the command_value
hols the payload with necessary additional information, specific to the device (here for instance, it holds a nested payload, with metadata along with an internal id required to update the real object). In the payload, the {{on}}
notation allows templating with the variables defined in thingin_attributes.
{
"iot_attributes": [
{
"name": "on",
"value": "$[0].value.state.on"
},
{
"name": "bri",
"value": "$[0].value.state.bri"
},
{
"name": "sat",
"value": "$[0].value.state.sat"
}
],
"thingin_attributes": [
{
"name": "on",
"value": "{on}",
"frequency_sec": 60,
"command_value":{
"request": {
"connector": "mqtt",
"value": {
"req": "{\"on\":{{on}}}",
"arg": {
"type": "light",
"id": "00:17:88:01:03:20:6d:49-0b"
}
}
}
}
},
{
"name": "bri",
"value": "{bri}",
"frequency_sec": 60,
"command_value":{
"request": {
"connector": "mqtt",
"value": {
"req": "{\"bri\":{{bri}}}",
"arg": {
"type": "light",
"id": "00:17:88:01:03:20:6d:49-0b"
}
}
}
}
},
{
"name": "sat",
"value": "{sat}",
"frequency_sec": 60,
"command_value":{
"request": {
"connector": "mqtt",
"value": {
"req": "{\"sat\":{{sat}}}",
"arg": {
"type": "light",
"id": "00:17:88:01:03:20:6d:49-0b"
}
}
}
}
}
]
}
Platforms can be created by provider and then be used for several DTs. Currently, the supported authentification methods for the platforms are :
name
: the name of the platform (without spaces), that will then be used when creating a DTdescription
(optional)base_url
: base URL for the platformdata_get_prefix
: prefix added to base_url and concatenated to uuid_on_platform
to get data for a specific objectdata_get_suffix
: suffix concatenated to command_id_on_platform
to get data for a specific objectcommand_prefix
: prefix added to base_url
and concatenated to command_id_on_platform
to update data to the IoT platform when its state changes in Thing'incommand_suffix
: suffix concatenated to command_id_on_platform
to update data to the IoT platform when its state changes in Thing'inauthentication
: authentication mode amoung api_key
, none
, login_password
token_header
: Header value that must be used to provide api key in case of api_key or login_password authent. Use Bearer
for a Bearer authauth_path
: Path to auth endpoint (for login_password authent)auth_template
: Template build request to auth endpoint (for login_password authent). Basic
for a Basic authauth_response
: Template to extract token from auth answer (for login_password authent)auth_headers
: List of additional headers for authent request (for login_password authent)E.g. of the live_objects platform:
{
"name": "live_objects",
"description": "Live object platform",
"base_url": "https://liveobjects.orange-business.com/",
"data_get_suffix": "",
"data_get_prefix": "api/v0/data/streams/",
"command_prefix": "api/v1/deviceMgt/devices/",
"command_suffix": "/commands/",
"authentication": "api_key",
"token_header": "X-API-KEY"
}
The SDT module use a specific thing'in user to update the data of the avatar, this user must have rights on the avatar's DT. That's why an avatar associated to a SDT must be visible. If you want to restrict access to this avatar, you can use a predefined ACLs (accessible by GET /sdts/acl endpoint) that allow this user to update DPs and read the whole avatar, as well as allowing the owner to do everything with the avatar. You can also create your own ACLs but you must give rights to the dt user.
Statements of the predefined ACL:
[
{
"condition": {
"$eq": [
"$user.external_uuid",
"dt_user"
]
},
"rules": [
{
"effect": "Allow",
"action": [
"Update"
],
"resources": [
".{.*}"
]
},
{
"effect": "Allow",
"action": [
"Read"
],
"resources": [
"."
]
}
]
},
{
"condition": {
"$eq": [
"$user.uuid",
"$avatar.owner"
]
},
"rules": [
{
"effect": "Allow",
"action": [
"Read",
"Update",
"Delete"
],
"resources": [
"*"
]
}
]
}
]
See the dedicated page ThingDescription