Build Your First Digital Twin Model
In this tutorial, you’ll learn how to build a very simple digital twin model.
First, decide whether you’d like to build your model with C#, Java, or low-code Business Rules. Then follow the instructions below for your preferred language.
Note
If you would like to skip this step and deploy the model immediately, you can download the finished files from here. Then you can jump directly to the Deploy Your Model section.
Install Digital Twin Templates
Install Templates
Run the following command to install Digital Twin project templates. This will enable you to access Digital Twin templates through Visual Studio.
dotnet new install Scaleout.Modules.Templates
You can confirm that the templates were installed correctly by running:
dotnet new dt-rt --help
Create a Real-Time Project
Option 1: Visual Studio
Create a new project and select the ScaleOut Real-Time Digital Twin template.
Name the project MyRealTimeTwin (or another name of your choosing).
Option 2: Command Line
If you are using Linux (or you would rather use the command line to create your project), run the following command to create a real-time digital twin project:
dotnet new dt-rt -n MyRealTimeTwin
The ScaleOut Digital Twin Maven Archetypes generate a Java project tailored for real-time digital twin applications — ready to deploy to the ScaleOut Digital Twins™ service or an on-premises deployment.
Make sure the following tools are installed:
Java JDK 8 or later
Use the Maven Archetype Plugin to generate the quickstart project:
mvn archetype:generate \
-DarchetypeGroupId=com.scaleoutsoftware.archetypes \
-DarchetypeArtifactId=scaleout-realtime-digitaltwin \
-DarchetypeVersion=3.0.0 \
-DgroupId=com.mycompany.digitaltwin \
-DartifactId=java-digitaltwin-quickstart \
-Dpackage=com.digitaltwin.example \
-DtwinClassName=MyRealtimeTwin \
-DinteractiveMode=false
This will create a new project folder named java-digitaltwin-quickstart with the following classes located in the src/main/java/ directory’s com.digitaltwin.example package:
MyRealTimeTwin.javaMyRealTimeTwinMessageProcessor.javaExampleMessage.javaMain.java
We’ll finish implementing these classes in the following steps.
Implement the Model
Digital Twin Model
A digital twin model is a template that represents a group of real-world entities, like IoT devices or vehicles. Each digital twin instance corresponds to a specific entity and uses the data structure defined in the model.
A model can contain real-time data, static values, and computed values that are derived when it receives new data. In this basic example, our model only contains a single string property.
Open the file MyRealTimeTwinModel.cs. The class “MyRealTimeTwinModel” has been generated for you. Add the following property inside the class:
public class MyRealTimeTwinModel : DigitalTwinBase<MyRealTimeTwinModel>
{
public string? CurrentValue { get; set; }
}
From your IDE of choice (IntelliJ, Eclipse, or VS Code) open the file MyRealtimeTwin.java and add the following String property, getter, and setter:
package com.digitaltwin.example;
import com.scaleoutsoftware.digitaltwin.abstractions.DigitalTwinBase;
public class MyRealtimeTwin extends DigitalTwinBase<MyRealtimeTwin> {
public String _currentValue;
public String getCurrentValue() {
return _currentValue;
}
public void setCurrentValue(String value) {
_currentValue = value;
}
}
Open the ScaleOut Model Development Tool program. Click “New Model…” when prompted.
On the left sidebar, select Model Name. Name your model “MyRealTimeTwin” and click Update.
Under Model Definition > Instance Properties, click + Add New Property. Give the property the following values:
Name: currentValue
Type: String
Leave the “Initial Value” field blank. Click Add to Model to add the property.
Messages
A message is an object that holds data sent from a device to its corresponding digital twin instance. If you’re running a simulation, messages can also be sent by simulated devices. In this step, we define the structure of the message object. For this simple example, it only has one string property.
Find the file called ExampleMessage.cs in the Messages project. Rename it MyRealTimeTwinMessage.cs (or another name of your choosing). If prompted to perform a rename, select “Yes”.
The MyRealTimeTwinMessage class should contain a single string property: “MyProperty”. Rename this property to StringPayload.
From your IDE of choice (IntelliJ, Eclipse, or VS Code) open the file ExampleMessage.java and add the following String property, constructor, and getter.
package com.digitaltwin.example;
public class ExampleMessage {
private String _stringPayload;
public ExampleMessage(String stringPayload) {
_stringPayload = stringPayload;
}
public String getStringPayload() {
return _stringPayload;
}
}
Under Incoming Messages > Message Properties, click + Add New Property. Give the property the following values:
Name: StringPayload
Type: String
Click Add to Model to add the property.
Message Processor
When the digital twin system receives new messages from devices, it needs to process those messages and update the corresponding instances. We implement the message processing code in the Message Processor class. The Message Processor can simply update the instance properties with the new values from the message, or it can run more complex logic like computing a moving average or deciding whether to raise an alert.
For this example, we simply update the digital twin instance’s currentValue property to be the value of the StringPayload from the incoming message. We also log a notification with the instance ID and the contents of the message.
Open the file MyRealTimeTwinMessageProcessor.cs.
Replace the ProcessMessageAsync method with the following:
public override Task<ProcessingResult> ProcessMessageAsync(
ProcessingContext<MyRealTimeTwinModel> context,
MyRealTimeTwinModel digitalTwin,
byte[] msgBytes)
{
// Deserialize the message bytes into our specific message type.
MyRealTimeTwinMessage? message = System.Text.Json.JsonSerializer.Deserialize<MyRealTimeTwinMessage>(msgBytes);
if (message is null)
return Task.FromResult(ProcessingResult.NoUpdate);
// Modify the instance's state based on the message content.
digitalTwin.CurrentValue = message.StringPayload;
// The SOSS object was modified, so return DoUpdate to indicate that
// it should be updated in the ScaleOut service.
return Task.FromResult(ProcessingResult.DoUpdate);
}
From your IDE of choice (IntelliJ, Eclipse, or VS Code) open the file MyRealTimeTwinMessageProcessor.java and replace the processMessages method with the following snippet that logs the twins currentValue to the ScaleOut DigitalTwin streaming service:
import com.google.gson.Gson;
import com.scaleoutsoftware.digitaltwin.abstractions.MessageProcessor;
import com.scaleoutsoftware.digitaltwin.abstractions.ProcessingContext;
import com.scaleoutsoftware.digitaltwin.abstractions.ProcessingResult;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
public class MyRealtimeTwinMessageProcessor extends MessageProcessor<MyRealtimeTwin> {
@Override
public ProcessingResult processMessage(ProcessingContext<MyRealtimeTwin> processingContext, MyRealtimeTwin instance, byte[] message) {
try {
Gson gson = new Gson();
ExampleMessage msg = gson.fromJson(new String(message, StandardCharsets.UTF_8), ExampleMessage.class);
instance.setCurrentValue(msg.getStringPayload());
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
sw.flush();
processingContext.logMessage(Level.SEVERE, "Exception thrown by id" + processingContext.getDataSourceId() + " " + sw.toString());
}
return ProcessingResult.UpdateDigitalTwin;
}
}
We’ll test these changes on the workbench in the next section.
We’ll be adding two message processing rules: one to update the digital twin instance, and the other to log a notification.
Under Message Rules, click + Add New Message Rule.
For the first rule, name it “UpdateValue”. In the Text field, add the following rule:
DO currentValue = Incoming.StringPayload
Check the Hints field to confirm the rule is valid. Then click Add to Model.
Repeat the process for the second rule. Name it “LogMessage”. For the text, add the rule:
DO LOG_MESSAGE(0, "The real-time digital twin '" + Id + "' says '" + Incoming.StringPayload + "'")
Click Add to Model. You should see the two rules, UpdateValue and LogMessage, listed under Message Rules.
In the next step, you’ll learn how to test a digital twin model before deployment.