Interact with the platform
- Creating and reading entities and characteristics → Orchestrator REST API
- Saving and reading real-time metrics and states → IIoT Middleware
- Reading historical metrics and states → HDM REST API
This is the multi-page printable view of this section. Click here to print.
The Orchestrator REST API enables to create and read all the different kinds of Digital Twin entities described in Model section.
This API is available through a dedicated Swagger interface for each Clawdite instance. Furthermore, it is possible to
generate API clients for several languages, such as Python, Java and JavaScript. The mentioned clients are already
generated and available within each Clawdite instance and make it possible to interact with Clawdite’s Orchestrator
from
external components.
In the following a few examples on entities management will be provided.
In order to use the generated API clients inside external components it is needed to correctly setup and install the dependencies. Note that you need a personal GitLab token for accessing the registries. In case you don’t have it please contact the project’s maintainers.
pip install orchestrator-python-client --index-url https://__token__:<your_personal_token>@gitlab-core.supsi.ch/api/v4/projects/86/packages/pypi/simple<dependencies>
<dependency>
<groupId>ch.supsi.dti.isteps.hdt</groupId>
<artifactId>orchestrator-java-client</artifactId>
<version>0.2.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab-core.supsi.ch/api/v4/projects/86/packages/maven</url>
</repository>
</repositories>In order to create a Worker entity (or a FactoryEntity in general) it is mandatory to define the
associated FactoryEntityModelCategoty and FactoryEntityModel in advance.
import os
from datetime import datetime
import orchestrator_python_client as hdt_client
from orchestrator_python_client import ApiClient, FactoryEntityModelCategoryDto, FactoryEntityModelDto, WorkerDto
# NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
configuration = hdt_client.Configuration(host=os.getenv('HDT_ENDPOINT'))
configuration.api_key['apiKeyAuth'] = os.getenv('HDT_API_KEY')
api_client = hdt_client.ApiClient(configuration)
factory_entity_model_category_api = hdt_client.FactoryEntityModelCategoryApi(api_client)
factory_entity_model_api = hdt_client.FactoryEntityModelApi(api_client)
worker_api = hdt_client.WorkerApi(api_client)
operator_category = factory_entity_model_category_api.create_factory_entity_model_category(
FactoryEntityModelCategoryDto(name="Operator",
description="description")).payload
worker_model = factory_entity_model_api.create_factory_entity_model(
FactoryEntityModelDto(name="Worker",
description="description",
factory_entity_model_categories_id=[operator_category.id])).payload
worker = worker_api.create_worker(
WorkerDto(creation_date=datetime.now().isoformat(),
factory_entity_model_id=worker_model.id)).payloadimport java.util.Collections;
import java.time.LocalDateTime;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.FactoryEntityModelCategoryApi;
import org.openapitools.client.api.FactoryEntityModelApi;
import org.openapitools.client.api.WorkerApi;
import org.openapitools.client.model.FactoryEntityModelCategoryDto;
import org.openapitools.client.model.FactoryEntityModelDto;
import org.openapitools.client.model.WorkerDto;
private void createWorker() {
// NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
ApiClient apiClient = new ApiClient().setBasePath(System.getenv("HDT_ENDPOINT"));
String apiKey = System.getenv("HDT_API_KEY");
if(apiKey != null && !apiKey.isEmpty())
apiClient.addDefaultHeader("x-api-key", apiKey);
final FactoryEntityModelCategoryApi factoryEntityModelCategoryApi = new FactoryEntityModelCategoryApi(apiClient);
final FactoryEntityModelApi factoryEntityModelApi = new FactoryEntityModelApi(apiClient);
final WorkerApi workerApi = new WorkerApi(apiClient);
FactoryEntityModelCategoryDto operatorCategory = factoryEntityModelCategoryApi.createFactoryEntityModelCategory(
new FactoryEntityModelCategoryDto()
.setName("Operator")
.setDescription("description"));
FactoryEntityModelDto workerModel = factoryEntityModelApi.createFactoryEntityModel(
new FactoryEntityModelDto()
.setName("Worker")
.setDescription("description")
.setFactoryEntityModelCategoriesId(Collections.singletonList(operatorCategory.getId())));
WorkerDto worker = workerApi.createWorker(
new WorkerDto()
.setCreationDate(LocalDateTime.now().toString())
.setFactoryEntityModelId(workerModel.getId()));
}In order to retrieve a Worker entity (or an entity in general) it is mandatory to specify the associated entity ID.
import os
import orchestrator_python_client as hdt_client
from orchestrator_python_client import ApiClient, WorkerDto
# NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
configuration = hdt_client.Configuration(host=os.getenv('HDT_ENDPOINT'))
configuration.api_key['apiKeyAuth'] = os.getenv('HDT_API_KEY')
api_client = hdt_client.ApiClient(configuration)
worker_api = hdt_client.WorkerApi(api_client)
# NOTE: you need to specify the worker_id UUID
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker = worker_api.get_worker_by_id(worker_id)import java.util.Collections;
import java.time.LocalDateTime;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.WorkerApi;
import org.openapitools.client.model.WorkerDto;
private void readWorker() {
// NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
ApiClient apiClient = new ApiClient().setBasePath(System.getenv("HDT_ENDPOINT"));
String apiKey = System.getenv("HDT_API_KEY");
if(apiKey != null && !apiKey.isEmpty())
apiClient.addDefaultHeader("x-api-key", apiKey);
final WorkerApi workerApi = new WorkerApi(apiClient);
// NOTE: you need to specify the workerId UUID
workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
WorkerDto worker = workerApi.getWorkerById(workerId);
}Despite the creation of a FunctionalModule entity in not dependent on other entities, it is important to define the
associated FunctionalModuleInput, FunctionalModuleOutput and Block in order to correctly create
the StateDescriptor related to the FunctionalModule (i.e. its output that will be sent to the IIoT Middleware).
import os
from datetime import datetime
import orchestrator_python_client as hdt_client
from orchestrator_python_client import ApiClient, FunctionalModuleDto, FunctionalModuleInputDto,
FunctionalModuleOutputDto, NumberBasedDto, StateDescriptorDto
# NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
configuration = hdt_client.Configuration(host=os.getenv('HDT_ENDPOINT'))
configuration.api_key['apiKeyAuth'] = os.getenv('HDT_API_KEY')
api_client = hdt_client.ApiClient(configuration)
functional_module_api = hdt_client.FunctionalModuleApi(api_client)
functional_module_input_api = hdt_client.FunctionalModuleInputApi(api_client)
functional_module_output_api = hdt_client.FunctionalModuleOutputApi(api_client)
number_based_api = hdt_client.NumberBasedApi(api_client)
state_descriptor_api = hdt_client.StateDescriptorApi(api_client)
custom_module = functional_module_api.create_functional_module(
FunctionalModuleDto(name="CustomModule", description="description")).payload
custom_module_input = functional_module_input_api.create_functional_module_input(
FunctionalModuleInputDto(input_param_name="hr", path="HR", functional_module_id=custom_module.id,
descriptor_id=hr_descriptor.id)).payload
custom_module_output = functional_module_output_api.create_functional_module_output(
FunctionalModuleOutputDto(functional_module_id=custom_module.id,
output_param_name="CustomPrediction")).payload
number_based_dto = number_based_api.create_number_based(NumberBasedDto()).payload
custom_module_state_descriptor = state_descriptor_api.create_state_descriptor(
StateDescriptorDto(functional_module_output_id=custom_module_output.id, # to know the origin of the State
blockId=number_based_dto.id, # link the data structure
name="CustomModuleState",
description="prediction",
factory_entity_model_id=worker_model.id) # the prediction is related workers
).payloadimport java.util.Collections;
import java.time.LocalDateTime;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.FactoryEntityModelCategoryApi;
import org.openapitools.client.api.FactoryEntityModelApi;
import org.openapitools.client.api.WorkerApi;
import org.openapitools.client.model.FactoryEntityModelCategoryDto;
import org.openapitools.client.model.FactoryEntityModelDto;
import org.openapitools.client.model.WorkerDto;
private void createFunctionalModule() {
// NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
ApiClient apiClient = new ApiClient().setBasePath(System.getenv("HDT_ENDPOINT"));
String apiKey = System.getenv("HDT_API_KEY");
if(apiKey != null && !apiKey.isEmpty())
apiClient.addDefaultHeader("x-api-key", apiKey);
final FunctionalModuleApi functionalModuleApi = new FunctionalModuleApi(apiClient);
final FunctionalModuleInputApi functionalModuleInputApi = new FunctionalModuleInputApi(apiClient);
final FunctionalModuleOutputApi functionalModuleOutputApi = new FunctionalModuleOutputApi(apiClient);
final NumberBasedApi numberBasedApi = new NumberBasedApi(apiClient);
final StateDescriptorApi = new StateDescriptorApi(apiClient);
FunctionalModuleDto customModule = FunctionalModuleApi.createFunctionalModule(
new FunctionalModuleDto()
.setName("CustomName")
.setDescription("description"));
FunctionalModuleInputDto customModuleInput = FunctionalModuleInputApi.createFunctionalModuleInput(
new FunctionalModuleInputDto()
.setInputParameterName("hr")
.setPath("HR")
.setFunctionalModuleId(customModule.getId())
.setDescriptorId(hrDescriptor.getId()));
FunctionalModuleOutputDto customModuleOutput = FunctionalModuleOutputApi.createFunctionalModuleOutput(
new FunctionalModuleOutputDto()
.setFunctionalModuleId(customModule.getId())
.setOutputParameterName("CustomPrediction"));
NumberBasedDto numberBased = NumberBasedApi.createNumberBased(new NumberBasedDto());
StateDescriptorDto customModuleStateDescriptor = StateDescriptorApi.createStateDescriptor(
new FunctionalModuleOutputDto()
.setFunctionalModuleOutputId(customModuleOutput.getId()) // to know the origin of the State
.setBlockId(numberBased.getId()) // link the data structure
.setName("CustomModuleState")
.setDescription("prediction")
.setFactoryEntityModelId(workerModel.getId())); // the prediction is related workers
}The IIoT Middleware enables dynamic data published from Gateways and Functional Modules to be collected and made
available to other interested modules, such as the HDM which is in charge of persisting them.
Currently only the MQTT protocol is supported, so modules need to publish and subscribe to specific topics. MQTT clients
are available for different languages, in the following a few examples in Python and Java will be provided.
Please refer to the official documentation to learn more about how to use the client in your project.
The topic schema is HDT/{factory_entity_id}/{measurement/state}/{descriptor_id}/{value}.
The message schema is {timestamp}#{value}.
In order to publish a metric value to the IIoT Middleware for making it available to other components, specific topics structure and message format need to be used.
Note that, if the metric to be saved is composed by multiple fields, then the associated values need to be separated by a pipe "|".
For example: "1752760778790#1|2|3.
import os
from datetime import datetime
from paho.mqtt.client import Client
from paho.mqtt.enums import CallbackAPIVersion
def on_connect(client, userdata, flags, reason_code, properties):
loguru.logger.debug(f'Connected with result code "{reason_code}"')
# NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER and MQTT_PASSWORD environment variables
mqtt_client = Client(client_id='unique-id', callback_api_version=CallbackAPIVersion.VERSION2)
mqtt_client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASSWORD"))
mqtt_client.on_connect = on_connect
mqtt_client.connect(os.getenv('MQTT_HOST'), int(os.getenv("MQTT_PORT")))
quality_of_service = 1
# NOTE: you need to specify the measurement_descriptor_id and worker_id UUIDs
measurement_descriptor_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
value = 15.0
mqtt_client.publish(f'HDT/{worker_id}/measurement/{measurement_descriptor_id}',
f'{int(datetime.now().timestamp() * 1000)}#{value}', quality_of_service)
time.sleep(1) # wait for the messages to be sent
mqtt_client.disconnect()
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
private void publishMetric() {
// NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER and MQTT_PASSWORD environment variables
String broker = "tcp://" + System.getenv("MQTT_HOST") + ":" + System.getenv("MQTT_PORT");
String clientId = "unique-id";
int qos = 1;
// NOTE: you need to specify the measurement_descriptor_id and worker_id UUIDs
String measurementDescriptorId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
String workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
double value = 15.0;
try {
MqttClient mqttClient = new MqttClient(broker, "unique-id");
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName(System.getenv("MQTT_USER"));
connOpts.setPassword(System.getenv("MQTT_PASSWORD").toCharArray());
// Set callback for connection
mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println("Connected to " + serverURI);
}
@Override
public void connectionLost(Throwable cause) {
System.out.println("Connection lost: " + cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
// Not used in this case, since we are publishing only
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("Message delivered successfully");
}
});
mqttClient.connect(connOpts);
long timestamp = System.currentTimeMillis();
String message = timestamp + "#" + value;
mqttClient.publish("HDT/" + workerId + "/measurement/" + measurementDescriptorId,
new MqttMessage(message.getBytes()));
TimeUnit.SECONDS.sleep(1);
mqttClient.disconnect();
} catch (MqttException | InterruptedException e) {
e.printStackTrace();
}
}In order to publish a state value to the IIoT Middleware for making it available to other components, specific topics structure and message format need to be used.
import os
from datetime import datetime
from paho.mqtt.client import Client
from paho.mqtt.enums import CallbackAPIVersion
def on_connect(client, userdata, flags, reason_code, properties):
loguru.logger.debug(f'Connected with result code "{reason_code}"')
# NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER and MQTT_PASSWORD environment variables
mqtt_client = Client(client_id='unique-id', callback_api_version=CallbackAPIVersion.VERSION2)
mqtt_client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASSWORD"))
mqtt_client.on_connect = on_connect
mqtt_client.connect(os.getenv('MQTT_HOST'), int(os.getenv("MQTT_PORT")))
quality_of_service = 1
# NOTE: you need to specify the state_descriptor_id and worker_id UUIDs
state_descriptor_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
value = {"fatigue": [5, 10]}
mqtt_client.publish(f'HDT/{worker_id}/state/{state_descriptor_id}',
f'{int(datetime.now().timestamp() * 1000)}#{value}', quality_of_service)
time.sleep(1) # wait for the messages to be sent
mqtt_client.disconnect()
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
private void publishState() {
// NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER and MQTT_PASSWORD environment variables
String broker = "tcp://" + System.getenv("MQTT_HOST") + ":" + System.getenv("MQTT_PORT");
String clientId = "unique-id";
int qos = 1;
// NOTE: you need to specify the state_descriptor_id and worker_id UUIDs
String stateDescriptorId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
String workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
String value = "{\"fatigue\": [5, 10]}";
try {
MqttClient mqttClient = new MqttClient(broker, "unique-id");
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName(System.getenv("MQTT_USER"));
connOpts.setPassword(System.getenv("MQTT_PASSWORD").toCharArray());
// Set callback for connection
mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println("Connected to " + serverURI);
}
@Override
public void connectionLost(Throwable cause) {
System.out.println("Connection lost: " + cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
// Not used in this case, since we are publishing only
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
System.out.println("Message delivered successfully");
}
});
mqttClient.connect(connOpts);
long timestamp = System.currentTimeMillis();
String message = timestamp + "#" + value;
mqttClient.publish("HDT/" + workerId + "/state/" + stateDescriptorId,
new MqttMessage(message.getBytes()));
TimeUnit.SECONDS.sleep(1);
mqttClient.disconnect();
} catch (MqttException | InterruptedException e) {
e.printStackTrace();
}
}In order to read real-time metric values published to the IIoT Middleware, it is mandatory to subscribe to the topics of interest and to specify a callback for managing the received message.
import os
import time
from paho.mqtt.client import Client
from paho.mqtt.enums import CallbackAPIVersion
# NOTE: you need to specify the measurement_descriptor_id and worker_id UUIDs
def on_connect(client, userdata, flags, reason_code, properties):
measurement_descriptor_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
topic = f'HDT/{worker_id}/measurement/{measurement_descriptor_id}'
client.subscribe(topic, qos=1)
def on_message(client, userdata, msg):
print(f'Received message: {msg.payload.decode()} on topic {msg.topic}')
# NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER, and MQTT_PASSWORD environment variables
mqtt_client = Client(client_id='unique-id', callback_api_version=CallbackAPIVersion.VERSION2)
mqtt_client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASSWORD"))
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.connect(os.getenv('MQTT_HOST'), int(os.getenv("MQTT_PORT")))
mqtt_client.loop_start()import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import java.util.UUID;
private void readMetric() {
// NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER, and MQTT_PASSWORD environment variables
String broker = "tcp://" + System.getenv("MQTT_HOST") + ":" + System.getenv("MQTT_PORT");
String clientId = UUID.randomUUID().toString();
// NOTE: you need to specify the measurementDescriptorId and workerId UUIDs
String measurementDescriptorId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
String workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
topic = "HDT/"+workerId+"/measurement/"+measurementDescriptorId;
try {
MqttClient mqttClient = new MqttClient(broker, clientId);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName(System.getenv("MQTT_USER"));
connOpts.setPassword(System.getenv("MQTT_PASSWORD").toCharArray());
// Set callback for connection and message reception
mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println("Connected to " + serverURI);
}
@Override
public void connectionLost(Throwable cause) {
System.out.println("Connection lost: " + cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String receivedMessage = new String(message.getPayload());
System.out.println("Message received on topic " + topic + ": " + receivedMessage);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// Not used in this case, since we are subscribing only
}
});
mqttClient.connect(connOpts);
mqttClient.subscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
}In order to read real-time state values published to the IIoT Middleware, it is mandatory to subscribe to the topics of interest and to specify a callback for managing the received message.
import os
import time
from paho.mqtt.client import Client
from paho.mqtt.enums import CallbackAPIVersion
# NOTE: you need to specify the state_descriptor_id and worker_id UUIDs
def on_connect(client, userdata, flags, reason_code, properties):
state_descriptor_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
topic = f'HDT/{worker_id}/state/{state_descriptor_id}'
client.subscribe(topic, qos=1)
def on_message(client, userdata, msg):
print(f'Received message: {msg.payload.decode()} on topic {msg.topic}')
# NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER, and MQTT_PASSWORD environment variables
mqtt_client = Client(client_id='unique-id', callback_api_version=CallbackAPIVersion.VERSION2)
mqtt_client.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASSWORD"))
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.connect(os.getenv('MQTT_HOST'), int(os.getenv("MQTT_PORT")))
mqtt_client.loop_start()import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import java.util.UUID;
private void readState() {
// NOTE: you need to specify the MQTT_HOST, MQTT_PORT, MQTT_USER, and MQTT_PASSWORD environment variables
String broker = "tcp://" + System.getenv("MQTT_HOST") + ":" + System.getenv("MQTT_PORT");
String clientId = UUID.randomUUID().toString();
// NOTE: you need to specify the stateDescriptorId and workerId UUIDs
String stateDescriptorId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
String workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
topic = "HDT/"+workerId+"/state/"+stateDescriptorId;
try {
MqttClient mqttClient = new MqttClient(broker, clientId);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName(System.getenv("MQTT_USER"));
connOpts.setPassword(System.getenv("MQTT_PASSWORD").toCharArray());
// Set callback for connection and message reception
mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println("Connected to " + serverURI);
}
@Override
public void connectionLost(Throwable cause) {
System.out.println("Connection lost: " + cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String receivedMessage = new String(message.getPayload());
System.out.println("Message received on topic " + topic + ": " + receivedMessage);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// Not used in this case, since we are subscribing only
}
});
mqttClient.connect(connOpts);
mqttClient.subscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
}The HDM REST API enables to get all the historical data related to metrics and states (i.e. dynamic data) that were
published to the IIoT Middleware and persisted through the HDM, as described
in Architecture section.
This API is available through a dedicated Swagger interface for each Clawdite instance. Furthermore, it is possible to
generate API clients for several languages, such as Python, Java and JavaScript. The mentioned clients are already
generated and available within each Clawdite instance and make it possible to interact with Clawdite’s HDM from
external components.
In the following a few examples on data retrieval will be provided. Independently on the type of data, there are 4 retrieval modalities:
X dataX data from a specific point in timetime-range (i.e. 1 hour, 1 day, 1 week…)time-interval (i.e. from date X to date Y)In order to use the generated API clients inside external components it is needed to correctly setup and install the dependencies. Note that you need a personal GitLab token for accessing the registries. In case you don’t have it please contact the project’s maintainers.
pip install hdm-web-python-client --index-url https://__token__:<your_personal_token>@gitlab-core.supsi.ch/api/v4/projects/137/packages/pypi/simple<dependencies>
<dependency>
<groupId>ch.supsi.dti.isteps.hdt</groupId>
<artifactId>hdm-web-java-client</artifactId>
<version>0.2.2</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab-core.supsi.ch/api/v4/projects/137/packages/maven</url>
</repository>
</repositories>In this example the last 10 metrics are retrieved. The use of the other retrieval modalities is similar.
import os
from datetime import datetime
import hdm_web_python_client as hdm_client
from orchestrator_python_client import ApiClient
# NOTE: you need to specify the HDM_ENDPOINT and HDM_API_KEY environment variables
configuration = hdm_client.Configuration(host=os.getenv('HDM_ENDPOINT'))
configuration.api_key['apiKeyAuth'] = os.getenv('HDM_API_KEY')
api_client = hdm_client.ApiClient(configuration)
hdm_api = hdm_client.HdmControllerApi(api_client)
# NOTE: you need to specify the measurement_descriptor_id and worker_id UUIDs
measurement_descriptor_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
values = hdm_api.read_last_values(abstract_descriptor_id=measurement_descriptor_id,
factory_entity_id=worker_id,
number_of_last_values=10) import java.util.Collections;
import java.time.LocalDateTime;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.HdmApi;
import org.openapitools.client.model.GenericValueDto;
import org.springframework.data.domain.Page;
private void readMetrics() {
// NOTE: you need to specify the HDM_ENDPOINT and HDM_API_KEY environment variables
ApiClient apiClient = new ApiClient().setBasePath(System.getenv("HDM_ENDPOINT"));
String apiKey = System.getenv("HDM_API_KEY");
if (apiKey != null && !apiKey.isEmpty())
apiClient.addDefaultHeader("x-api-key", apiKey);
final HdmApi hdmApi = new HdmApi(apiClient);
// NOTE: you need to specify the measurementDescriptorId and workerId UUIDs
measurementDescriptorId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
numberOfLastValues = 10;
Page<GenericValueDto> values = hdmApi.readLastValues(measurementDescriptorId, workerId, numberOfLastValues);
}In this example the last 10 states are retrieved. The use of the other retrieval modalities is similar.
import os
from datetime import datetime
import hdm_web_python_client as hdm_client
from orchestrator_python_client import ApiClient
# NOTE: you need to specify the HDM_ENDPOINT and HDM_API_KEY environment variables
configuration = hdm_client.Configuration(host=os.getenv('HDM_ENDPOINT'))
configuration.api_key['apiKeyAuth'] = os.getenv('HDM_API_KEY')
api_client = hdm_client.ApiClient(configuration)
hdm_api = hdm_client.HdmControllerApi(api_client)
# NOTE: you need to specify the state_descriptor_id and worker_id UUIDs
state_descriptor_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
worker_id = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
values = hdm_api.read_last_values(abstract_descriptor_id=state_descriptor_id,
factory_entity_id=worker_id,
number_of_last_values=10)import java.util.Collections;
import java.time.LocalDateTime;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.HdmApi;
import org.openapitools.client.model.GenericValueDto;
import org.springframework.data.domain.Page;
private void readStates() {
// NOTE: you need to specify the HDM_ENDPOINT and HDM_API_KEY environment variables
ApiClient apiClient = new ApiClient().setBasePath(System.getenv("HDM_ENDPOINT"));
String apiKey = System.getenv("HDM_API_KEY");
if (apiKey != null && !apiKey.isEmpty())
apiClient.addDefaultHeader("x-api-key", apiKey);
final HdmApi hdmApi = new HdmApi(apiClient);
// NOTE: you need to specify the stateDescriptorId and workerId UUIDs
stateDescriptorId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
workerId = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
numberOfLastValues = 10;
Page<GenericValueDto> values = hdmApi.readLastValues(stateDescriptorId, workerId, numberOfLastValues);
}The Orchestrator REST API enables to create and read all the Digital Twin entities described
in Model section, in particular the characteristics (i.e. quasi-static data). CharacteristicDescriptor and
CharacteristicValue are used in order to model operator skills (e.g., work experience, manual dexterity), besides the
general features (e.g., sex, age, handedness).
This API is available through a dedicated Swagger interface for each Clawdite instance. Furthermore, it is possible to
generate API clients for several languages, such as Python, Java and JavaScript. The mentioned clients are already
generated and available within each Clawdite instance and make it possible to interact with Clawdite’s Orchestrator
from external components.
In the following a few examples about skills modelling will be provided.
In order to use the generated API clients inside external components it is needed to correctly setup and install the dependencies. Note that you need a personal GitLab token for accessing the registries. In case you don’t have it please contact the project’s maintainers.
pip install orchestrator-python-client --index-url https://__token__:<your_personal_token>@gitlab-core.supsi.ch/api/v4/projects/86/packages/pypi/simple<dependencies>
<dependency>
<groupId>ch.supsi.dti.isteps.hdt</groupId>
<artifactId>orchestrator-java-client</artifactId>
<version>0.2.3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab-core.supsi.ch/api/v4/projects/86/packages/maven</url>
</repository>
</repositories>In order to define a skill it is needed to create a CharacteristicDescriptor with an associated CharacteristicValue.
Note that a CharacteristicDescriptor is uniquely linked to an already existing FactoryEntityModel.
Moreover, the Worker (or FactoryEntity in general) which possesses the skill (i.e., CharacteristicValue) needs to
be defined in advance.
import os
from datetime import datetime
from collections import OrderedDict
import orchestrator_python_client as hdt_client
from orchestrator_python_client import ApiClient, FactoryEntityModelCategoryDto, FactoryEntityModelDto, WorkerDto,
CharacteristicDescriptorDto, CharacteristicValueDto, FieldType
# NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
configuration = hdt_client.Configuration(host=os.getenv('HDT_ENDPOINT'))
configuration.api_key['apiKeyAuth'] = os.getenv('HDT_API_KEY')
api_client = hdt_client.ApiClient(configuration)
factory_entity_model_category_api = hdt_client.FactoryEntityModelCategoryApi(api_client)
factory_entity_model_api = hdt_client.FactoryEntityModelApi(api_client)
worker_api = hdt_client.WorkerApi(api_client)
characteristic_descriptor_api = hdt_client.CharacteristicDescriptorApi(api_client)
characteristic_value_api = hdt_client.CharacteristicValueApi(api_client)
operator_category = factory_entity_model_category_api.create_factory_entity_model_category(
FactoryEntityModelCategoryDto(name="Operator",
description="description")).payload
worker_model = factory_entity_model_api.create_factory_entity_model(
FactoryEntityModelDto(name="Worker",
description="description",
factory_entity_model_categories_id=[operator_category.id])).payload
worker = worker_api.create_worker(
WorkerDto(creation_date=datetime.now().isoformat(),
factory_entity_model_id=worker_model.id)).payload
# "Gender" characteristic creation
gender_descriptor = characteristic_descriptor_api.create_characteristic_descriptor(
CharacteristicDescriptorDto(name="Gender",
description="Operator gender",
factory_entity_model_id=worker_model.id)).payload
worker_gender = characteristic_value_api.create_characteristic_value(
CharacteristicValueDto(values=OrderedDict({datetime.now().isoformat(): "Male"}),
type=FieldType.STRING,
characteristic_descriptor_id=gender_descriptor.id,
factory_entity_id=worker.id)).payload
# "Manual dexterity" skill creation
manual_dexterity_descriptor = characteristic_descriptor_api.create_characteristic_descriptor(
CharacteristicDescriptorDto(name="Manual dexterity",
description="Operator manual dexterity",
factory_entity_model_id=worker_model.id)).payload
worker_manual_dexterity = characteristic_value_api.create_characteristic_value(
CharacteristicValueDto(values=OrderedDict({datetime.now().isoformat(): "41"}),
type=FieldType.NUMBER,
characteristic_descriptor_id=manual_dexterity_descriptor.id,
factory_entity_id=worker.id)).payloadimport java.util.Collections;
import java.time.LocalDateTime;
import org.openapitools.client.ApiClient;
import org.openapitools.client.api.FactoryEntityModelCategoryApi;
import org.openapitools.client.api.FactoryEntityModelApi;
import org.openapitools.client.api.WorkerApi;
import org.openapitools.client.api.CharacteristicDescriptorApi;
import org.openapitools.client.api.CharacteristicValueApi;
import org.openapitools.client.model.FactoryEntityModelCategoryDto;
import org.openapitools.client.model.FactoryEntityModelDto;
import org.openapitools.client.model.WorkerDto;
import org.openapitools.client.model.CharacteristicDescriptorDto;
import org.openapitools.client.model.CharacteristicValueDto;
import org.openapitools.client.model.FieldType
private void createSkill() {
// NOTE: you need to specify the HDT_ENDPOINT and HDT_API_KEY environment variables
ApiClient apiClient = new ApiClient().setBasePath(System.getenv("HDT_ENDPOINT"));
String apiKey = System.getenv("HDT_API_KEY");
if(apiKey != null && !apiKey.isEmpty())
apiClient.addDefaultHeader("x-api-key", apiKey);
final FactoryEntityModelCategoryApi factoryEntityModelCategoryApi = new FactoryEntityModelCategoryApi(apiClient);
final FactoryEntityModelApi factoryEntityModelApi = new FactoryEntityModelApi(apiClient);
final WorkerApi workerApi = new WorkerApi(apiClient);
final CharacteristicDescriptorApi characteristicDescriptorApi = new CharacteristicDescriptorApi(apiClient);
final CharacteristicValueApi characteristicValueApi = new CharacteristicValueApi(apiClient);
FactoryEntityModelCategoryDto operatorCategory = factoryEntityModelCategoryApi.createFactoryEntityModelCategory(
new FactoryEntityModelCategoryDto()
.setName("Operator")
.setDescription("description"));
FactoryEntityModelDto workerModel = factoryEntityModelApi.createFactoryEntityModel(
new FactoryEntityModelDto()
.setName("Worker")
.setDescription("description")
.setFactoryEntityModelCategoriesId(Collections.singletonList(operatorCategory.getId())));
WorkerDto worker = workerApi.createWorker(
new WorkerDto()
.setCreationDate(LocalDateTime.now().toString())
.setFactoryEntityModelId(workerModel.getId()));
// "Gender" characteristic creation
CharacteristicDescriptorDto genderDescriptor = characteristicDescriptorApi.createCharacteristicDescriptor(
new CharacteristicDescriptorDto()
.setName("Gender")
.setDescription("Worker gender")
.setFactoryEntityModelId(workerModel.getId()));
CharacteristicValueDto workerGender = characteristicValueApi.createCharacteristicValue(
new CharacteristicValueDto()
.setValues(new TreeMap<>() {{
put(LocalDateTime.now().toString(), "Male");
}})
.setType(FieldType.STRING)
.setCharacteristicDescriptorId(genderDescriptor.getId())
.setFactoryEntityId(worker.getId()));
// "Manual dexterity" skill creation
CharacteristicDescriptorDto manualDexterityDescriptor = characteristicDescriptorApi.createCharacteristicDescriptor(
new CharacteristicDescriptorDto()
.setName("Manual dexterity")
.setDescription("Worker anual dexterity")
.setFactoryEntityModelId(workerModel.getId()));
CharacteristicValueDto workerManualDexterity = characteristicValueApi.createCharacteristicValue(
new CharacteristicValueDto()
.setValues(new TreeMap<>() {{
put(LocalDateTime.now().toString(), "41");
}})
.setType(FieldType.NUMBER)
.setCharacteristicDescriptorId(manualDexterityDescriptor.getId())
.setFactoryEntityId(worker.getId()));
}