Connect IoT - Talking to MES Tutorial#
Overview#
A controller and MES talk through three channels, each with its own tasks:
| Channel | Who starts it | Tasks |
|---|---|---|
| The workflow asks MES | The workflow | Execute Service Call, Execute Action, Entity Instance, Get Configurations, Create Notification, Adjust State, API Post Event |
| MES asks this controller instance | MES, for example a DEE action that calls SendRequest or Publish on the instance | System Action Listener with Send System Action Reply, and Ready State Requested with Send Ready State Reply |
| The message bus | Any process that sends on a subject | Send Message Bus Message, and Message Bus Listener with Message Bus Reply |
A system action reaches only the instance it is sent to, and its action group only tells the messages of that instance apart. A message bus subject is global: every listener of the subject hears it. That difference decides the channel when MES has something to tell the line.
In this tutorial, you add one Data Flow page to an existing controller. A DEE action asks the controller instance three questions, and the workflow answers each one: a load limit read from a configuration entry, the Resource that the instance represents, and a recipe obtained over the message bus. The workflow also raises a notification for each limit request. The tutorial is for integrators who completed the basic configuration tutorial. It extends Connect IoT - MES Interoperability Scenarios Tutorial, where MES transactions send the requests, with the general request and reply tasks.
Info
For more information, see System Action Listener, Message Bus Listener, and Retry Mechanism.
Before You Start#
- Have an Automation Controller with the Workflow Type
Data Flowand an instance connected to a Resource, such asResource-A, and an Automation Manager that you can start in console mode, for example from Connect IoT - Basic Configuration Tutorial. - Make sure you can create and execute DEE actions (DEE Actions) and create configuration entries (Configuration).
- Check the values of the
NotificationTypeandNotificationSeveritylookup tables of your installation, such asGeneralandInformation.
Sequence of Steps#
Step 1: Create a DEE Action That Asks the Instance#
A DEE action reaches a controller instance through the Resource it is connected to. SendRequest sends a request under an action group and waits for the answer; Publish sends a notification that nothing answers.
Go to Administration > DEE Actions, select New, and create the action AskController with the classification ConnectIoT and this code:
UseReference("Cmf.Foundation.BusinessObjects.dll", "Cmf.Foundation.BusinessObjects");
UseReference("Cmf.Foundation.BusinessOrchestration.dll", "");
UseReference("", "Cmf.Foundation.Common.Exceptions");
UseReference("", "Cmf.Foundation.Common");
UseReference("Cmf.Navigo.BusinessObjects.dll", "Cmf.Navigo.BusinessObjects");
UseReference("%MicrosoftNetPath%Microsoft.CSharp.dll", "");
var serviceProvider = (IServiceProvider)Input["ServiceProvider"];
IResource resource = serviceProvider.GetService<IResource>();
resource.Name = Input["Resource"] as string;
resource.Load();
var instance = resource.GetAutomationControllerInstance();
if (instance == null)
{
throw new Exception("Resource not connected to any IoT instance");
}
// Ask this instance only, under the action group given, and wait up to 10 seconds
dynamic reply = instance.SendRequest(Input["Group"] as string, null, 10000);
Input.Add("Answer", reply == null ? "Nothing received" : reply.ToString());
Select Validate. The syntax check passes, and the action is ready to execute with the inputs Resource and Group.
Step 2: Answer a Request from MES#
Open the controller, add a Data Flow page named Talk to MES, and place the tasks below:
| Task | Settings to set | Inputs and outputs to link |
|---|---|---|
System Action Listener, named On limit request | Action Group load.limit; keep Auto Enable on and Reply Timeout 60000 | - |
Send System Action Reply, named Answer the limit | Keep Default Reply {} | Success of On limit request to Activate |
Select Save, and stop and start the controller instance in Automation > Connect IoT so that it runs the new page. Repeat this after each later change to the workflow.
Execute AskController with Resource set to Resource-A and Group set to load.limit. The Answer output holds {}: the reply received no value, so the task sent its Default Reply.
Warning
A reply task answers the request of the run in which it is activated. Activate it from the run that the listener started, as here; activated anywhere else, it emits an error and MES receives nothing. See Zones.
Step 3: Answer with a Configuration Value#
Get Configurations reads configuration entries, values that belong to the installation and change without a new controller version.
- Go to Administration > Configuration, create the entries for the path
/Cmf/Custom/ConnectIoT/, and create in it the entryMaxLoadwith the typeStringand the value25. - On the
Talk to MESpage, addGet Configurations, namedRead the limit, and on its Outputs tab add the outputmaxLoadwith the typeInteger, the full path/Cmf/Custom/ConnectIoT/MaxLoad, and the default value-1. The canvas shows the output asmaxLoad, and its stored port name ismaxLoadOut. -
Replace the link into
ActivateofAnswer the limit, and link the tasks as follows:From To SuccessofOn limit requestActivateofRead the limitmaxLoadofRead the limitReplyofAnswer the limit, with theAny To AnyconverterSuccessofRead the limitActivateofAnswer the limit
Execute AskController again with the group load.limit. The answer holds reply with the value 25: an object is sent as it is, and any other value is wrapped as {"reply": <value>}. The value is converted to the type of the output, and an entry that is missing or empty emits the default value with a warning, followed by Success.
Edit MaxLoad to 0, and execute the action once more without restarting the instance. The answer holds reply with the value 0, read on this request. In 12.0, Send System Action Reply, Message Bus Reply, and Send Ready State Reply send the Default Reply only when no value arrived since their previous answer, so 0 and false are sent as answers.
Step 4: Tell the Operators with a Notification#
Add Create Notification, named Notify the request, and link Success of Read the limit to its Activate. In its settings:
- Leave Name empty, so that MES names each notification. MES holds one notification per name, so a fixed name creates the first notification and fails every later one.
- Set Type to
General, Title toMES asked for the load limit, and Severity to a value of your installation, such asInformation. - Set Assignment to
Everyone, and keep the clearance ModeManualSingleUser, which needs no Valid To date.
Execute AskController twice with the group load.limit. Each execution adds a new notification for every user.
Step 5: Hand Over the Resource of the Instance#
Entity Instance hands the workflow the entity that the controller instance, or one of its driver instances, is attached to, so one workflow serves every instance.
- Add a second
System Action Listener, namedOn resource request, with the Action Groupresource.describe. - Add
Entity Instance, namedThis instance's Resource, and choose the entity of the controller when the designer asks. - Add a second
Send System Action Reply, namedAnswer with the Resource. - Link
Successof the listener toActivateofEntity Instance,instancetoReply, andSuccessofEntity InstancetoActivateofAnswer with the Resource.
Execute AskController with the group resource.describe. The answer holds the Resource, with the Name Resource-A.
Choose the task that calls MES from what it needs to reach:
| Task | Use it when | What to know |
|---|---|---|
Entity Instance | You need the entity of this instance or of a driver instance | Loaded once and kept: later activations call MES only with Reload in every change on |
Execute Service Call | One MES service answers the need, such as GetObjectByName for an entity that a request names | Each input port carries the bare property name of the service, such as Name. Each output port is named output$<property>, such as output$Instance, read in Control Flow as {{ $<block name>.output$Instance }}. An input renamed input$<property> is sent with the prefix, and MES does not find the value |
Execute Action | The work needs several services, or one transaction | Runs the DEE action of a Rule with the scope ConnectIoT, with one added input per value. The inputs input accepts only a Map |
In Data Flow, an added input of Execute Service Call or Execute Action keeps the last value it received, so deliver a value on every activation.
Step 6: Ask over the Message Bus#
A message bus request is answered by whichever listener subscribes to its subject: another controller, an MES application, or, here, the same workflow.
| Task | Settings to set | Inputs and outputs to link |
|---|---|---|
Message Bus Listener, named Recipe service | Subject recipe.lookup | - |
Message Bus Reply, named Answer recipe questions | Default Reply {"recipe": "R-7"} | Success of Recipe service to Activate |
System Action Listener, named On recipe request | Action Group recipe.describe | - |
Send Message Bus Message, named Ask for the recipe | Message Type Request, Subject recipe.lookup, Message {"product": "P-100"}, Timeout 5000 | Success of On recipe request to Activate |
Send System Action Reply, named Answer with the recipe | - | Reply of Ask for the recipe to Reply; Success of Ask for the recipe to Activate |
Execute AskController with the group recipe.describe. The answer holds recipe with the value R-7. A Notification message type is sent without waiting, and its Success means the message was handed to the bus, not that anyone received it. A Request waits up to Timeout for an answer and emits Error when none arrives.
Note
Send an MES identifier inside an object, such as {"Id": "2102050000000000003"}. Text received on the Message input is parsed as JSON, so a bare 19-digit identifier becomes a number that loses its last digits, and text that is not JSON is sent as {}.
Validate the Result#
Execute AskController with Resource set to Resource-A and each group:
| Group | Answer | Also |
|---|---|---|
load.limit | reply with the current value of MaxLoad | A new notification |
resource.describe | The Resource Resource-A | - |
recipe.describe | recipe with the value R-7 | - |
nothing.here | Nothing received, after the 10-second timeout | No listener subscribes to the group |
When nothing answers within the timeout, SendRequest returns null, and the action reports Nothing received. It raises an exception only when the workflow replies with an error.
When a Call to MES Fails#
The tasks that call MES share three retry settings:
- Number of Retries (default
30) counts the attempts of the controller, made only for the transient failures listed in Retry Mechanism, such as a deadlock, data changed since last viewed, or a refused connection. Any other failure is reported once onError. - Sleep Time between retries (ms) (default
1000) is the wait after each failed attempt. - Number of System Retries (default
10) is meant for MES, which retries the service on its side. In 12.0,Execute Action,API Post Event,Get Configurations, andResolve Tablesend it to MES. OnExecute ActionandAPI Post Event, a value received on thenumberOfRetriesinput replaces the setting.
Execute Service Call always sends 10 to MES, whatever its Number of System Retries holds, and Entity Instance and Adjust State do not send the setting. Number of Retries and Sleep Time between retries (ms) work on every task that calls MES.
Link Error wherever a failure matters. In Control Flow, an error ends the branch. Execute Service Call with no service selected is an exception: it emits a text on Error, and a Control Flow branch continues as if the call succeeded.
Control Flow Differences#
| Topic | Data Flow | Control Flow |
|---|---|---|
| Answering a request | Send System Action Reply or Message Bus Reply in the run of the listener | The value returned by the handler branch: an object as it is, any other value as {"reply": <value>}, and {} when the branch ends without Return |
| Answering a ready-state request | Send Ready State Reply | The returned value; false when the branch ends without Return |
| Reply Timeout passes | The listener emits Error and answers with an error; a later reply is still sent | The branch stops, and the listener answers with an error |
| Switching a listener on and off | The Enable/Disable input | Keep Auto Enable on and set the group or subject in the settings |
Give each request group or subject one listener that answers: two listeners on one group both answer the same request. Two listeners on a notification are safe, because both hear it and neither answers.
Zero downtime uses the same pattern: when an Automation Scheduled Action uses the DefinedInWorkflow detector, MES sends a CheckForReadyState request, Ready State Requested receives it, and the workflow answers with Send Ready State Reply. Anything but true, including a timeout, counts as not ready. See Scenario 4 - Controller Version Update - Workflow Ready Signal.
Next Steps#
Enable the out-of-the-box interoperability scenarios of a Resource in Connect IoT - MES Interoperability Scenarios Tutorial, which use the same request and reply pattern for setup, material, container, and recipe transactions. To understand why a Data Flow task sends the last value it held, see Connect IoT - How Values Travel Tutorial, and to build the same answers in Control Flow, see Connect IoT - Control Flow in Depth Tutorial.
