Connect IoT - Advanced Configuration Tutorial#
Estimated time to read: 32 minutes
This tutorial builds upon the (Basic and Intermediate) configuration tutorial settings and will attempt to integrate data read from an equipment while applying some workflow logic to the retrieved value. In the basic tutorial we had an OPC-UA integration, which connected to an OPC-UA server, in the intermediate we posted to a Data Collection.
In the Advanced Tutorial, we will first make the integration configurable in terms of connection settings, then we will address the scenario where we have a setup of a resource where we set the setpoint to 200ºC and validate it. When the setpoint reaches the 200ºC the user will be able to perform a Track In and post the temperature to a Data Collection. After 1 minute it will perform the Track Out of the Material. An additional requirement is the ability to collect temperature values on demand.
Note
During this tutorial, the Automation Manager will run in console mode in order to highlight the most important events as they take place.
MES Model#
Let's start with building the model for this tutorial:
- Create a Calendar
- Create a Facility
- Create an Area
- Create a Resource named
Oven - Create a Step named
Oven Step - Create a Service
Oven Service- Add the service to the Resource Services
- Add the service to the Step Context
- Create a Flow named
Oven Flowwith theOven Step - Create a Product named
Product Oven- Give as default flow path the Flow
Oven Flowand the StepOven Step
- Give as default flow path the Flow
- Create a Material
Oven Material - Dispatch the
Oven Materialto the ResourceOven
If the Oven Material is not dispatchable to the Resource Oven, please revalidate your model.
Note
You can always change the model to what best suits you. This tutorial is not focused in MES modeling so it will be very brief on this topic. Also, feel free to use the model you have from previous tutorials and add the parts that are missing from your model.
Automation Driver Definition#
Let's go over the Automation Driver Definition Oven DD and set the properties. In this case we will not need events, only properties and commands.
Note
Note that to do this in a real life context, it is important to have a general knowledge about the protocol, the equipment itself and its related documentation.
Properties#
Go to Automation Driver Definition, select the Oven DD and then select Edit.
To add the TemperatureSetPoint property:
- Skip the General Data step
- Add a new entry to the list of Properties by selecting
- In the Property details, provide:
- A name that represents the Property name
- A description
- The NodeID - identification of the Property - check the equipment documentation for the actual identification of the property on the equipment
- The type (for classification and reporting purposes)
- The
WritableandReadableflags - The data type of the Property in OPC UA format - check the equipment documentation for the actual data type of the property on the equipment
In this case we have no commands or events. If we chose to add any command of event, they would be defined in the appropriate tabs.
Automation Controller#
Let's go over the Automation Controller Oven Controller and define the logic that will support the described scenario.
Setup#
First, let's review how we are addressing the setup. Currently, we have the values statically defined in the workflow, but in order to reuse the same controller for different entities, we need the workflow to be a bit more dynamic. Let's start with the following steps:
-
Drag and drop the following tasks:
- Get Configurations: to retrieve Configurations from the system (
Administration > Configurations) - Entity Instance: to assess the associated entity
- Get Configurations: to retrieve Configurations from the system (
-
Connect the output of
OnSetupof theOn Equipment Setuptask to theEntity Instanceactive - Remove the link of
OnInitializeto theconnectlink - In the
Get Configurationstask:- Create input
resourceName- Inputs in theGet Configurationscan be used as tokens - Create output
Address - Give as path
/Custom/ConnectIoT/OPC-UA/${resourceName}/Address- notice${resourceName}will be replaced by the defined input - Type as
String
- Create input
- Link the
Entity Instanceinstance to the activate of theGet Configurations - Link the
Entity Instanceinstance to the resource name input of theGet Configurations - The instance comes with the full object payload and we just need the
Name- Create converter
AnyToAny - Create converter
GetObjectProperty- With path
Name - Type
String
- With path
- Create converter
- Link the
Get Configurationssuccess to connect of theOn Equipment Setuptask - Go to
Administration > Configuration - Click
Create - Create configuration entries until you have the desired path of
/Custom/ConnectIoT/OPC-UA/Oven - Create the config that will hold the value
- In the
NamewriteAddress - In the
TypeselectString - Set the value with the proper address (i.e
opc.tcp://localhost:48101)
- In the
- Link the output
Addressof theGet Configurationsto theOnEquipmentSetupAddressinput
Now, the hook to determine the address will no longer be the Automation Controller but rather the configuration for a particular resource in the configurations entry. This is a simple way to make our controller fully dynamic and in that way promote its reusability throughout different resources of the same type. There are other mechanisms to hold these values such as saving in Entity Attributes or on a separate table, both of these are also out of the box supported by tasks, with the Entity Instance task and the Resolve Table task.
On Demand - Show Temperature#
One of the interesting applications of Connect IoT is providing direct feedback to a GUI, in order to have a more powerful and symbiotic integration between the equipment and the operator. The goal of our GUI is to be able to retrieve and display the latest temperature value. This is a very simple example, but it will provide the basic building blocks of the system.
Create a DEE - GetCurrentTemperature#
Let's create a DEE to retrieve the Temperature from Connect IoT.
- Go to
Administration > DEE Actions - Select
New - Give as Name
GetCurrentTemperature - Give Classification
ConnectIoT - Use the following code:
// Retrieve Service Provider
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
IResource resource = serviceProvider.GetService<IResource>();
// Retrieve Resource Name from the Inputs
resource.Name = Input["Resource"] as string;
resource.Load();
var instance = resource.GetAutomationControllerInstance();
// Validate there's an Automation Controller instance for this resource
if (instance == null) {
throw new Exception("Resource not connected to any IoT instance");
}
else
{
// Request value from Connect IoT and wait for the reply
dynamic payload = instance.SendRequest("Cmf.Request.Temperature", null, 10000);
Input.Add("Value", payload["reply"].ToString());
}
In the DEE execution, it will receive a resource name, resolve the instance linked to the resource and send a message to Connect IoT and wait for a reply.
- Go to
BusinessData > Rule - Select
New - Give as Name
GetCurrentTemperature - Give as Scope
ConnectIoT - DEE Action
GetCurrentTemperature- if it does not appear in the search box, validate that the DEE Classification is correct
Automation Controller - Retrieve Temperature#
In the Automation Controller it should now, upon the message received from the DEE, retrieve and reply back with the temperature value.
- Go to
Oven Controller - In the Workflow, create a new page
On Demand - Get Temperature -
Drag and drop the following tasks:
- On System Event: to subscribe to the message bus topic
Cmf.Request.Temperature - Get Equipment Properties: to get the value of the temperature
- On System Event: to subscribe to the message bus topic
-
Go to the
On System Eventsettings and for the Action Group, writeCmf.Request.Temperature. -
In the
Get Equipment Properties Valuestask- Add as Output, the Automation Property
Temperature
- Add as Output, the Automation Property
- Link the
On System Eventoutputdatato theGet Equipment Properties ValuesActivate input - Link the
Get Equipment Properties ValuesTemperatureoutput to the inputreply -
Add a converter
AnyToAny
Test with the DEE#
Start the OPC UA Server mentioned in the previous (Basic and Intermediate) tutorials and start your Automation Manager, making sure you have the correct address configured in the configuration entry for your resource, which in this case should follow along the lines of /Custom/ConnectIoT/OPC-UA/Oven/Address. Go to the DEE that we have created (GetCurrentTemperature) and select the Execute button. You can now perform executions of the DEE.
Let's add an input Resource with Value Oven (or whatever Resource you have linked to the controller instance). Select Execute.
Notice how we can easily test our implementation with DEEs. Now let's create a GUI.
Create a GUI - Retrieve and Show Temperature#
MES supports an out of the box approach to create UI pages directly, in the system, without the need to code.
- Go to
Administration > UIPages - Select
New- Give the Name
Collect Temperatures - Press
Create
- Give the Name
- Select
Edit -
Drag and drop the following Widgets:
Form: to be able to select a Resource from the systemButton: to trigger the action of getting the temperature- Feel free to go to the settings and give it a friendly name like
Get Current Temperature
- Feel free to go to the settings and give it a friendly name like
Text: to trigger the action of getting the temperature- Feel free to go to the settings and give it a friendly name like
Current Temperature
- Feel free to go to the settings and give it a friendly name like
-
In the
ForminSettings > Fields - Add a field
Resource- Type -
ReferenceType - Reference type -
Entity - Reference type name -
Resource
- Type -
-
In the
Settings-
In
Properties, we will define the static variables global variables that we will need- Add a new property for the GUI to know the DEE to execute
- Name -
DeeName - Source -
Static - Type -
String - Value -
GetCurrentTemperature
- Name -
- Add a new property for the GUI to know the input of the DEE
- Name -
Resource - Source -
Static - Type -
String - Value -
Resource
- Name -
- Add a new property for the GUI to know the value of the input of the DEE
- Name -
[input]Resource - Source -
Static - Type -
String - Value -
Oven(this is just a default value)
- Name -
- Add a new property for the GUI to know the value of the output of the DEE with the temperature
- Name -
Temperature - Source -
Static - Type -
String - Value -
Value(this matches the input we added to the DEEGetCurrentTemperature)
- Name -
- Add a new property for the GUI to know the DEE to execute
-
In
Data Sources, we will define the services we need to call to execute the DEE- Add a new datasource for the GUI to Load the DEE to execute
- Name -
LoadDEE - Type -
ServiceCall - Retrieve data on start -
false - Retrieve data on changes -
false - Select
Settings- Choose
DynamicExecutionEngine- Select
GetActionByName
- Select
- Choose
- Name -
- Add a new datasource for the GUI to execute the DEE
- Name -
Request Temperature - Type -
ServiceCall - Retrieve data on start -
false - Retrieve data on changes -
false - Show error feedback messages -
true - Select
Settings- Choose
DynamicExecutionEngine- Select
ExecuteAction
- Select
- Choose
- Name -
- Add a new datasource for the GUI to Load the DEE to execute
-
Press
Save and Close
-
-
In the right pane, select
Links- Drag and drop the
Formwidget - Link the
Formoutputfield$ResourceChangeto thePageinput[input]Resource- Add the converter
entityName. This will retrieve the Resource name.
- Add the converter
- Drag and drop the
LoadDee - Link the output of
PageDeeNameto the input ofLoadDeeName - Drag and drop the button
GetCurrentTemperature - Link the button
GetCurrentTemperatureoutputOnButtonClickto the inputrefreshof theLoadDee. This means that every time you press the button it will refresh this widget - Drag and drop the widget
Request Temperature - Connect the output of the
Page[input]Resourceto the InputInputof theRequest Temperature- Apply the converter
setMapValuewith converter parameterResource. This will associate the value of the property resource, which in this case is the constant stringResourcewith the value of the[input]Resource. Creating a Map of keyResourceand value, the value that was fed to the[input]Resource, in this case the actual resource name.
- Apply the converter
- Link the output
output$Actionof theLoadDeetoActioninput of theRequest Temperaturerefreshinput of theRequest Temperature
- Drag and drop the widget
Text - Link the
output$Outputof theRequest Temperatureto the inputtextof theTextwidget - Apply the converter
anyToStringPropertywith converter parameterTemperature. This will look into the output map for a key of the value that is declared in the propertyTemperature, in this case isValue.
- Drag and drop the
-
Press
Save
The page is now fully usable. Provide a resource to the form that does not have a controller instance you should see an exception popup as a banner.
If we select the Oven resource and press the button Get Current Temperature we will see now the temperature is show in the text box.
Note
If the DEE has multiple Inputs, the methodology is the same but with multiple links to the input Input.
Set Setpoint - On Resource Begin Setup#
The use case can be further built upon if we consider that this value was set externally (e.g. through a recipe). Right now the focus is just to show the interaction between the system and Connect IoT. The goal is to have a Setup for a Resource in the MES that can only be complete if the Setpoint is set to 200ºC.
We will create a DEE with the value 200ºC statically defined that will send a message to IoT and await confirmation in the Resource Complete Setup action. This value could be changed to come from a recipe, a definition in a table, a configuration or some other definition in the system in order to have the implementation become dynamic.
Create a DEE - SetSetpointTo200#
In order to be able to request an action to be performed appended to a system interaction we will need to create a hook on the action of the Begin Setup. The way to implement this in the MES system is through the use of DEEs that can be appended in the system actions either in Pre (before execution), or Post (after execution). These actions are within the transaction of the action performed, so if they give an error the whole transaction will rollback and maintain consistency in the system.
- Go to
Administration > DEE Actions - Select
New - Give as Name
SetSetpointTo200, for now the classification and action group is not important
The DEE code is split between two important sections. The condition phase and the execution phase. Only if the condition phase returns with true, will the execution phase be invoked. In the history of an action in the MES this will also be explicit, if a DEE is appended. For more information on DEEs, see DEE Actions.
The context of the DEE, that is present on the Inputs dictionary, will depend on where the DEE is hooked.
Let's add the Action Group to our DEE.
- Go to the
Detailstab - Press
Addon the Action Group - Search for
ResourceManagement.ResourceManagementOrchestration.BeginSetup.Post - Check it and press
Add
If in step 3. the action group is not present:
- Go to
Administration > DEE Actions - Select the Settings (three vertical dots) next to the
Action Groups - Select
Add new Action Group - Give as
Name-ResourceManagement.ResourceManagementOrchestration.BeginSetup.Post - Select
Create
In order to find the action group where we want to append our DEE, you can consult the API documentation ⧉, or analyze the history whenever the action that you are interested is executed and it will be apparent what are multiple sub-actions that you can append your business logic. Note also that in the DEE in the code view, in the right pane it Input Parameters, it will now show all available parameters.
Starting on the code for the Test Condition Code. We want to validate that the Inputs that we are interested are correct, to validate we should process and then pass that value to our DEE context.
/// <summary>
/// Summary text: Send Setpoint to IoT on Begin Setup
/// Actions groups:
/// * ResourceManagement.ResourceManagementOrchestration.BeginSetup.Post
/// Depends On:
/// Is Dependency For:
/// Exceptions:
/// </summary>
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
// Validate input
if (Input["BeginSetupInput"] is not BeginSetupInput beginSetupInput)
{
throw new ArgumentNullCmfException("BeginSetupInput");
}
return true;
// Cmf
UseReference("Cmf.Foundation.Common.dll", "Cmf.Foundation.Common.LocalizationService");
UseReference("Cmf.Navigo.BusinessOrchestration.dll", "Cmf.Navigo.BusinessOrchestration.ResourceManagement.InputObjects");
UseReference("Cmf.Common.CustomActionUtilities.dll", "Cmf.Common.CustomActionUtilities");
UseReference("Cmf.Common.CustomActionUtilities.dll", "Cmf.Common.CustomActionUtilities.Abstractions");
// Other Dependencies
UseReference("Newtonsoft.Json.dll", "Newtonsoft.Json");
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
var localizationService = serviceProvider.GetService<ILocalizationService>();
var utilitiesDeeContext = serviceProvider.GetService<IDeeContextUtilities>();
// Collect inputs
var resource = (Input["BeginSetupInput"] as BeginSetupInput).Resource as IResource;
var instance = resource.GetAutomationControllerInstance();
if (instance == null) {
throw new Exception("Resource not connected to any IoT instance");
}
else
{
string commandMessage = JsonConvert.SerializeObject(
(
new Dictionary<string, object>
{
{ "DEE", "SetSetpoint200" },
{ "Action", "SetSetpoint"},
{ "Value", 200}
}
), Newtonsoft.Json.Formatting.Indented);
dynamic payload = instance.SendRequest("Cmf.Perform.Action", commandMessage, 10000);
if(payload == null) {
throw new Exception("Nothing received" );
} else if(!bool.Parse(payload["reply"].ToString())) {
throw new Exception("Setpoint is not 200ºC" );
}
}
Let's take a look at the code execution. The goal is to send a message to Connect IoT, based on the Resource. In order to perform communication to Connect IoT we will use the message bus through a Send Request. The Message Bus supports a "fire and forget" method using Publish as well as methods that wait for a success acknowledgement which is the case of Send Request.
The execution will send the message to the Controller Instance linked to the resource and will wait for the acknowledge of a reply. It will only succeed if it receives an expected true value.
Set Setpoint - Automation Controller#
On the Begin Setup we are now broadcasting a message to the Connect IoT layer. Let's now implement the logic of performing equipment integration actions with that information. In IoT we will receive the message and set the setpoint.
- Go to
Oven Controller - In the Workflow, create a new page
Manage Setpoint -
Drag and drop the following tasks:
- On System Event: to subscribe to the message bus topic
Cmf.Perform.Action - Set Equipment Properties Values: to set the value of temperature setpoint
- On System Event: to subscribe to the message bus topic
-
Go to the
On System Eventsettings and for the Action Group, writeCmf.Perform.Action. - In the
Set Equipment Properties Values- Add as Input, the Automation Property
TemperatureSetPoint
- Add as Input, the Automation Property
- Link the
On System Eventoutputdatato theSet Equipment Properties Values- Activate
- The
TemperatureSetPoint- Apply the converter
Get Object Property- Path
Value - Type
Decimal
- Path
- Apply the converter
- Link the
Set Equipment Properties ValuesSuccessto the Reply of theOn System Eventtask- Apply the converter
AnyToAny
- Apply the converter
Test with the Automation#
In the Resource Oven, select Begin Setup and press Begin.
Notice that in UA Expert, the tag for the temperature setpoint is now 200ºC as expected.
Validate Setpoint - On Resource Complete Setup#
In the Begin Setup, we've set the setpoint, but we only want the Complete Setup to be possible if the temperature matches the setup. We will then use the same DEE to validate the temperature on the Complete Setup.
Change a DEE - SetSetpointTo200#
Let's add the Action Group to our DEE.
- Go to the
Detailstab - Press
Addon the Action Group - Search for
ResourceManagement.ResourceManagementOrchestration.CompleteSetup.Post - Check it and press
Add
If in step 3. the action group is not present:
- Go to
Administration > DEE Actions - Select the Settings (three vertical dots) next to the
Action Groups - Select
Add new Action Group - Give as
Name-ResourceManagement.ResourceManagementOrchestration.CompleteSetup.Post - Select
Create
Perform the steps described in add the Action Group to the DEE.
/// <summary>
/// Summary text: Send Setpoint to IoT on Begin Setup
/// Actions groups:
/// * ResourceManagement.ResourceManagementOrchestration.BeginSetup.Post
/// Depends On:
/// Is Dependency For:
/// Exceptions:
/// </summary>
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
// Validate input
var hasBeginSetup = Input.ContainsKey("BeginSetupInput") && Input["BeginSetupInput"] is BeginSetupInput;
var hasCompleteSetup = Input.ContainsKey("CompleteSetupInput") && Input["CompleteSetupInput"] is CompleteSetupInput;
if (!hasBeginSetup && !hasCompleteSetup)
{
throw new ArgumentNullCmfException("SetupInput");
}
return true;
// Cmf
UseReference("Cmf.Foundation.Common.dll", "Cmf.Foundation.Common.LocalizationService");
UseReference("Cmf.Navigo.BusinessOrchestration.dll", "Cmf.Navigo.BusinessOrchestration.ResourceManagement.InputObjects");
// Other Dependencies
UseReference("Newtonsoft.Json.dll", "Newtonsoft.Json");
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
var localizationService = serviceProvider.GetService<ILocalizationService>();
// Collect inputs
var hasBeginSetup = Input.ContainsKey("BeginSetupInput") && Input["BeginSetupInput"] is BeginSetupInput;
var resource = hasBeginSetup ? (Input["BeginSetupInput"] as BeginSetupInput).Resource:(Input["CompleteSetupInput"] as CompleteSetupInput).Resource;
var action = hasBeginSetup ? "BeginSetup": "CompleteSetup";
var message = new Dictionary<string, object>
{
{ "DEE", "SetSetpoint200" },
{ "Value", 200}
};
switch(action)
{
case "BeginSetup":
message.Add("Action", "SetSetpoint");
break;
case "CompleteSetup":
message.Add("Action", "ValidateSetpoint");
break;
default:
throw new Exception("Unknow Action");
}
var instance = resource.GetAutomationControllerInstance();
if (instance == null) {
throw new Exception("Resource not connected to any IoT instance");
}
else
{
string commandMessage = JsonConvert.SerializeObject(
(
message
), Newtonsoft.Json.Formatting.Indented);
dynamic payload = instance.SendRequest("Cmf.Perform.Action", commandMessage, 10000);
if(payload == null) {
throw new Exception("Nothing received" );
} else if(!bool.Parse(payload["reply"].ToString())) {
throw new Exception("Setpoint is not 200ºC"+payload["reply"].ToString() );
}
}
Notice the big change in the execution. We kept most of our code exactly the same but added a new context: the action. This action will be used to provide context to the Connect IoT layer to know that in one situation it must set the setpoint and in another situation it will validate that the temperature is in the setpoint.
Validate Setpoint - Automation Controller#
On the complete setup we are now broadcasting a message to the Connect IoT layer. Let's now validate the setpoint against the temperature.
- Go to
Oven Controller - In the Workflow, got to page
Manage Setpoint -
Drag and drop the following tasks:
- Switch: tto allow us to perform conditional Actions
- Get Equipment Properties Values: to set the value of temperature setpoint
- Expression Evaluator: to compare the setpoint against the temperature
-
In the
Switchtask add- Input
Actionof TypeString - Add Outputs
- SetSetpoint
- Equals - SetSetpoint
- Name - SetSetpoint
- Type - Boolean
- Value -
true
- ValidateSetpoint
- Equals - ValidateSetpoint
- Name - ValidateSetpoint
- Type - Boolean
- Value -
true
- SetSetpoint
- Input
- Link the output
datato theSwitchinput Action- Apply converter
GetObjectProperty- Path -
Action - Type -
String
- Path -
- Apply converter
- Link the output
SetSetpointto theActivateof theSet Equipment Properties Valuestask - Link the output
ValidateSetpointto theActivateof theGet Equipment Properties Valuestask -
In the
Expression Evaluator- Check the flag Clear inputs to
false - Add Inputs
- Setpoint
- Name -
Setpoint - Type -
Decimal - Default Value - 0
- Name -
- Temperature
- Name -
Temperature - Type -
Decimal - Default Value - 0
- Name -
- Setpoint
-
Add Outputs
- IsValid
- Name -
IsValid - Type -
String -
Expression:
- Name -
Notice that we are not doing an exact match, this is because the temperature oscillates between the setpoint. So we are putting a threshold of accepted values.
- IsValid
- Check the flag Clear inputs to
-
Link the
$Temperatureoutput- To the input Temperature of the
Validate Setpointtask - To the input Activate of the
Validate Setpointtask
- To the input Temperature of the
- Link the output
datato theExpression EvaluatorinputSetpoint- Apply converter
GetObjectProperty- Path -
Value - Type -
Decimal
- Path -
- Apply converter
- Link the
Get Equipment Properties Valuesto the- Input
$Temperatureof theExpression Evaluator - Input
Activateof theExpression Evaluator
- Input
- Link the
Expression EvaluatoroutputIsValidto the inputreplyof theOn System Event
Test with the Automation#
In the Resource Oven, if you have already set performed the Begin Setup operation on the Resource, perform the Complete Setup. If the temperature is now 1+-200ºC you should be successful, if not it will show an error message.
Post Data - On TrackIn#
As we saw when we were collecting values, the temperature varies in a threshold of the setpoint. So we want to collect the temperature at the time of the TrackIn, to keep track of the temperature that the material will be exposed at the time of the TrackIn.
One of the important things to consider in a DEE is that it will run every time the action is performed in the system. In the case that we are addressing we wish to be more specific and require that the action be performed only in particular steps. In order to achieve this, let´s add an attribute in our Step to flag it as a Step where we want the logic to execute.
Create a Step Attribute#
- Go to
Administration > Entity Types - Select the
Step - In the Attributes, select
Manage - Press the plus button to add
- Create a new attribute
- Name
NotifyEQOnTrackIn - Scalar Type
Bit - Update
- Name
- Press the
Generatebutton - Go to the
Oven Step - The attribute
NotifyEQOnTrackInwill now be visible under the list of Attributes Editthe attribute and change it to betrue
Create a DEE - NotifyIoTOnEquipmentTrackIn#
- Go to
Administration > DEE Actions - Select
New - Give as Name
NotifyIoTOnEquipmentTrackIn, for now the classification and action group is not important
Let's add the Action Group to our DEE.
- Go to the
Detailstab - Press
Addon the Action Group - Search for
BusinessObjects.MaterialCollection.TrackIn.Pre - Check it and press
Add
If in step 3. the action group is not present:
- Go to
Administration > DEE Actions - Select the Settings (three vertical dots) next to the
Action Groups - Select
Add new Action Group - Give as
Name-BusinessObjects.MaterialCollection.TrackIn.Pre - Select
Create
Starting on the code for the Test Condition Code. We want to validate that the Inputs that we are interested are correct, then check the Step of the Material to validate whether we should process it and subsequently pass that value to our DEE context.
/// <summary>
/// Summary text: Start production on material track in
/// Actions groups:
/// * BusinessObjects.MaterialCollection.TrackIn.Pre
/// Depends On:
/// Is Dependency For:
/// Exceptions:
/// </summary>
// Retrieve from Dependency Injection Container
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
bool isToExecute = false;
// Validate Inputs
if (Input["MaterialCollection"] is not IMaterialCollection materialCollection){
throw new ArgumentNullCmfException("MaterialCollection");
}
if (Input["Resource"] is not IResource resource) {
throw new ArgumentNullCmfException("Resource");
}
resource.Load();
var step = materialCollection.FirstOrDefault().Step;
step.LoadAttributes(new Collection<string>() {"NotifyEQOnTrackIn"});
// Only notify IoT if it's a notifyIoTStep
if (step.Attributes != null && step.Attributes.ContainsKey("NotifyEQOnTrackIn") && (bool)step.Attributes["NotifyEQOnTrackIn"])
{
isToExecute = true;
}
return isToExecute;
In the execution we will iterate through the Materials and for each one we will send a message to the Controller Instance linked to the Resource of the Material and wait for success. Bear in mind that if the wait time is very long or if no response is sent back from Connect IoT, the GUI will be in a loading screen and then eventually timeout, consider always replying back and handling the exception.
Note
By using the resource.GetAutomationControllerInstance(); and using then the instance to do a instance.SendRequest, you guarantee that only the controller instance associated to this Resource will be notified. If you want to broadcast every listener consider using the MessageBus native methods.
// Other Dependencies
UseReference("Newtonsoft.Json.dll", "Newtonsoft.Json");
// Retrieve from Dependency Injection Container
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
// Collect inputs
var resource = Input["Resource"] as IResource;
var materialsToStartProduction = Input["MaterialCollection"] as IMaterialCollection;
// Iterate through materials and send a message to IoT
foreach (var Material in materialsToStartProduction)
{
string commandMessage = JsonConvert.SerializeObject(
(
new Dictionary<string, object>
{
{ "DEE", "NotifyIoTOnEquipmentTrackIn" },
{ "Action", "PostToDataCollection"}
}
), Newtonsoft.Json.Formatting.Indented);
var instance = resource.GetAutomationControllerInstance();
if (instance == null) {
throw new Exception("Resource not connected to any IoT instance");
}
else
{
dynamic reply = instance.SendRequest("Cmf.Perform.Action", commandMessage, 10000);
if(reply == null) {
throw new Exception("Nothing received" );
}
}
}
In this example, let's choose a generic topic and a more complex payload. It is also correct to use the topic as the context for the action to be performed like Cmf.Post.Temperature. The goal was to demonstrate a more complex payload example.
Automation Controller - Implement Post Data#
Now that we have a DEE that will notify Connect IoT whenever there is a TrackIn. We will need to create a listener in the Oven Automation Controller and to perform a Post to the DataCollection.
- Go to
Oven Controller - In the Workflow, create a new page
Post Data - OnTrackIn -
Drag and drop the following tasks:
- On System Event: to subscribe to the message bus topic
Cmf.Perform.Action - Switch: to allow us to perform conditional Actions
- Get Equipment Properties Values: to retrieve the value of temperature
- Data Collection: to post data to a Data Collection
- On System Event: to subscribe to the message bus topic
-
Go to the
On System Eventsettings and for the Action Group, writeCmf.Perform.Action. - Go to the
Switchsettings- Add Input
Actionas String - Add Outputs
- Equals to
PostToDataCollection - Name
PostToDataCollection - Type
Boolean - Value
true
- Equals to
- Add Input
- Link the
On System Eventoutputdatato theSwitchinputAction- Apply the converter
Get Object Property- Path
Action - Type `String
- Path
- Apply the converter
- Link the
SwitchoutputPostToDataCollectionto theActivateof theGet Equipment Properties Values - Go to the
Get Equipment Properties Valuessettings and add in the outputs the Automation PropertyTemperature - Go to the
Data Collectionand configure like in the Intermediate Connect IoT Tutorial, but change theComplex Perform Data Collection ModetoPerform To Material - Link the
Get Equipment Properties ValuesTemperature output- To the
Data CollectionTemperature input - To the
Data Collectionactive input
- To the
- Link the
Successoutput of theData Collectiontask to the Reply of theOn System Eventtask - Link the
dataoutput of theOnSystemEventtask to thematerialof theData Collectiontask- Apply the converter
Get Object Property- Path
Material - Type
String
- Path
- Apply the converter
CreateSystemEntity- entityType
Material - identifier:
Name
- entityType
- Apply the converter
Create a Material and Dispatch and TrackIn#
Create a Material Oven Material with the Product Product Oven and dispatch it for the Resource Oven. Now track in the Material at the Resource Oven.
Now, if we go to the collected data of the Material it will show the data collection Temperature Oven with the value Temperate. Currently, the OPC-UA server is sending a temperature value with a large resolution, however if you prefer a more readable value feel free to apply an Expression Evaluator task to round up the value.
Automatic TrackOut - After 1 minute#
The material was tracked in successfully and we can now say that is being processed. We want to have a limited amount of time during which the material can be exposed to the setpoint temperature and then perform a TrackOut directly from the automation. We can use the default services provided out-of-the-box by the system and custom services, but for this case let's do a similar approach to the GUI. Using a DEE also allows us the opportunity to do some further customization if we wish to.
Create a DEE - PerformATrackOut#
Let's create a DEE to retrieve the Temperature from Connect IoT.
- Go to
Administration > DEE Actions - Select
New - Give as Name
PerformATrackOut - Give as Classification
ConnectIoT
// Retrieve Service Provider
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
IMaterial material = serviceProvider.GetService<IMaterial>();
// Retrieve Material Name from the Inputs
material.Name = Input["Material"] as string;
material.Load();
material.TrackOut();
In the DEE execution, which will receive a Material name, load the Material object and execute the TrackOut.
- Go to
BusinessData > Rule - Select
New - Give as Name
PerformATrackOut - Give as Scope
ConnectIoT - DEE Action
PerformATrackOut- if it does not appear in the search box, validate that the DEE Classification is correct
Automation Controller - TrackOut Automatically After 1 min#
In this implementation we will use the same topic as the TrackIn, we will start a timer that will trigger the Rule PerformATrackOut after 1 minute. We will require the Material name, but only after a minute, to perform the TrackOut.
Connect IoT executes the tasks asynchronously, depending on activation time. In cases where we know before hand that there is a big time frame difference and that inputs can be overriden while waiting for the termination of other tasks, it's strongly recommended to use either the Synchronize task or sub-workflows. The sub-workflows preserve the activation context when activated, so there is no problem to receive the Material and then wait for 1 minute, as the context for that sub-workflow will be preserved and further activations will be new instances of the sub-workflow. The sub-workflow has an execution timeout, so the execution may not exceed that timeout.
- Go to
Oven Controller - In the Workflow, create a new page
TrackOut Automatically - After 1 min -
Drag and drop the following tasks:
- On System Event: to subscribe to the message bus topic
Cmf.Perform.Action - Switch: to allow us to perform conditional Actions
- Workflow: to execute sub-workflows
- On System Event: to subscribe to the message bus topic
-
Go to the
On System Eventsettings and for the Action Group, writeCmf.Perform.Action. - Go to the
Switchsettings- Add Input
Actionas String - Add Outputs
- Equals to
PostToDataCollection - Name
PostToDataCollection - Type
Boolean - Value
true
- Equals to
- Add Input
- Link the
On System Eventoutputdatato theSwitchinputAction- Apply the converter
Get Object Property- Path
Action - Type `String
- Path
- Apply the converter
- In the Workflow, create a new page
Sub - TrackOut Automatically - After 1 min -
Drag and drop the following tasks:
Start: the start context of the sub-workflowEnd: the end result of the sub-workflowTimer: to allow us to perform conditional ActionsExecute Action: to execute sub-workflows
-
In the
Timertask open theSettings- Set the
Auto activatetofalse - Set the
intervalto60000 - Set the
Working ModetoNumber of Occurrencesto1
- Set the
- Link the output
Successof theTimerto theActivateof theExecute Action - Open the
Execute Actionsettings- Select the
Rule-PerformATrackOut - In the
Inputstab- Add a new input
- Name -
Material - Type -
String - Default Value -
N/A- can be whatever you wish as it wil be overriden
- Name -
- Add a new input
- Select the
- Link the output
Materialof the taskStartto theMaterialInput of theExecute Action - Link the output
SuccessandErrorto the matching inputs of theEndtask -
Go to the page
TrackOut Automatically - After 1 min -
In the
Workflowtask settings, select theAutomation WorkflowSub - TrackOut Automatically - After 1 min -
Link the output
dataof theOn System Eventto the inputMaterialof theWorkflowtask
Interestingly, look that we are not replying back, even though the message was a SendRequest, it's not a problem, because the SendRequest works as a success on the first reply, and that will be achieved by the workflow Post Data - OnTrackIn.
In order to test, let´s Abort our Material, Dispatch and TrackIn and let´s see the differences.
We can still see the previous reply, but now we register a new handler for our TrackOut. Then, after 1 minute:
You now have a built structure using Connect IoT to track the lifecycle of a Material lifecycle, the lifecycle of a Resource and to collect values. This is the end of the advanced configuration tutorial.




























