<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:discourse="http://discourse.org/rss/modules/discourse/"><channel><title>Luis Filipe Mascarenhas on DevBlog</title><link>https://devblog.criticalmanufacturing.com/author/luis-filipe-mascarenhas/</link><description>Recent content in Luis Filipe Mascarenhas on DevBlog</description><image><url>https://devblog.criticalmanufacturing.com/uploads/og.webp</url><link>https://devblog.criticalmanufacturing.com/uploads/og.webp</link></image><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>A template by [Heksagon](https://www.heksagon.net). Implemented for [Critical Manufacturing](https://www.criticalmanufacturing.com/).</copyright><lastBuildDate>Tue, 21 May 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://devblog.criticalmanufacturing.com/author/luis-filipe-mascarenhas/index.xml" rel="self" type="application/rss+xml"/><item><title>OPCUA Template - DynamicTags</title><link>https://devblog.criticalmanufacturing.com/blog/20240521_iot_dynamictags/</link><pubDate>Tue, 21 May 2024 00:00:00 +0000</pubDate><dc:creator>Luis Filipe Mascarenhas</dc:creator><guid>https://devblog.criticalmanufacturing.com/blog/20240521_iot_dynamictags/</guid><description>OPCUA Base Integration</description><content:encoded><![CDATA[<p>Showcasing the <code>Dynamic Tags</code> Package to Speed Up and Templatize OPC-UA Implementations</p>
<h2 id="introduction">Introduction</h2>
<p>This controller aggregates customers requirements on OPCUA implementations and is evolving to satisfy new requirements for on common scenarios.</p>
<h2 id="main-features">Main Features</h2>
<ul>
<li>Perform DataCollections</li>
<li>Execute machine state changes</li>
<li>Service and DEE calls</li>
<li>Recipe Management</li>
</ul>
<h2 id="perform-a-datacollection">Perform a DataCollection</h2>
<p>Performing a DataCollection can be triggered by:</p>
<ul>
<li>A timer elapsed or a cron job expression</li>
<li>A tag cycle counter</li>
</ul>
<h2 id="machine-state-change">Machine State Change</h2>
<p>A specified Tag value can be used to represent the actual machine state</p>
<h2 id="service-and-dee-calls">Service and DEE Calls</h2>
<ul>
<li>Call Service or DEE action on a Tag change event</li>
</ul>
<h2 id="recipe-management">Recipe Management</h2>
<ul>
<li>Support Recipe Parameters and Recipe Body</li>
<li>Uploading a Recipe from Equipment</li>
<li>Downloading a Recipe to Equipment</li>
</ul>
<p><em>In the following sections we will detail and provide usage scenarios for each use case.</em></p>
<h2 id="how-this-works">How this Works</h2>
<p>In this package, we use OPCUA Driver Extensions (<a href="https://help.criticalmanufacturing.com/userguide/business-data/automation-protocol/automation-protocol-protocols/driver_opcua/#driver-extensions" target="_blank" rel="noopener">https://help.criticalmanufacturing.com/userguide/business-data/automation-protocol/automation-protocol-protocols/driver_opcua/#driver-extensions</a>) to avoid being restricted to a specific Equipment Driver Definition.
The Controller behaviour is configured for each feature using these smart tables:</p>
<ul>
<li>
<p><ST>CustomIoTOPCUADataCollectionContext

<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuadatacollectioncontext.png" alt="&lt;ST&gt;CustomIoTOPCUADataCollectionContext" />

</p>
</li>
<li>
<p><ST>CustomIoTOPCUAExecutionContext

<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuaexecutioncontext.png" alt="&lt;ST&gt;CustomIoTOPCUAExecutionContext" />

</p>
</li>
<li>
<p><ST>CustomIoTOPCUARecipeContext

<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuarecipecontext.png" alt="&lt;ST&gt;CustomIoTOPCUARecipeContext" />

</p>
</li>
</ul>
<h2 id="common-repository">COMMON Repository</h2>
<p><code>COMMON</code> is a repository where projects can implement features that can be shared and reused. This mitigates the need to implement the same code across different projects. The features are posted to <code>COMMON</code> and every project is free to import, use and contribute back to make it even more robust.
The repository has two main branches: <code>development</code> and <code>development-10x</code>. Each one containing the corresponding controller version for each MES version:</p>
<p>MES versions up to V9.x: <a href="https://tfs-projects.cmf.criticalmanufacturing.com/ImplementationProjects/COMMON/_git/Packages?path=%2FFeatures%2FIoT-DynamicTags&amp;version=GBdevelopment&amp;_a=contents" target="_blank" rel="noopener">https://tfs-projects.cmf.criticalmanufacturing.com/ImplementationProjects/COMMON/_git/Packages?path=%2FFeatures%2FIoT-DynamicTags&version=GBdevelopment&_a=contents</a>
MES versions equal or greather than V10x: <a href="https://tfs-projects.cmf.criticalmanufacturing.com/ImplementationProjects/COMMON/_git/Packages?path=%2FFeatures%2FIoT-DynamicTags&amp;version=GBdevelopment-10x&amp;_a=contents" target="_blank" rel="noopener">https://tfs-projects.cmf.criticalmanufacturing.com/ImplementationProjects/COMMON/_git/Packages?path=%2FFeatures%2FIoT-DynamicTags&version=GBdevelopment-10x&_a=contents</a></p>
<h2 id="using-this-package-on-my-project">Using this package on my project</h2>
<p>To use this package on your project, add to your <code>repositories.json</code>:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/addcommontorepositories.png" alt="Adding to repositories.json" />


<em>PS: For V10x, add &ldquo;\\cmffs\public\PI_Common\Packages\CI\development-10x&rdquo; instead</em></p>
<p>Also, add to your <code>cmfpackage.json</code> file:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/addtoprojectcmfpackage.png" alt="Adding to repositories.json" />

</p>
<p><strong>Important</strong>: If your project is using a different patch version than the one this package was prepared for (in either V9 or V10), please use the components unrooted:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/addtoprojectdifferentmesversion.png" alt="Adding to Project" />

</p>
<h2 id="feature-configuration">Feature Configuration</h2>
<p>Available package options are described on package <a href="https://tfs-projects.cmf.criticalmanufacturing.com/ImplementationProjects/COMMON/_git/Packages?path=/Features/IoT-DynamicTags/README.md&amp;_a=preview" target="_blank" rel="noopener">README.md</a>.</p>
<p>Configuration is orchestrated on a smart table <code>&lt;ST&gt;IoTMetaDataDefinition</code> by name/value pairs. Used entries are:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Default/Example Values</th>
</tr>
</thead>
<tbody>
<tr>
<td>OPCUA_Address</td>
<td>The OPC server address to be used</td>
<td>opc.tcp://serverhostname:serverport</td>
</tr>
<tr>
<td>OPCUA_User</td>
<td>The user to access to the OPC server</td>
<td></td>
</tr>
<tr>
<td>OPCUA_Password</td>
<td>The password to access to the OPC server</td>
<td></td>
</tr>
<tr>
<td>OPCUA_SecurityPolicy</td>
<td>The security policy to be used to access to the OPC server</td>
<td></td>
</tr>
<tr>
<td>OPCUA_StateModel</td>
<td>The state model to be used</td>
<td>OPCUA</td>
</tr>
<tr>
<td>disableAutomation</td>
<td>To disable automation actions even when Communicating (Boolean)</td>
<td>false by default</td>
</tr>
<tr>
<td>DynamicTags_CreateNotificationDEE</td>
<td>DEE to be used to create Notification on disconnect</td>
<td></td>
</tr>
<tr>
<td>DynamicTags_DisconnectedNotificationTemplate</td>
<td>Notification Template to be used on disconnect</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="creating-a-controller-instance">Creating a Controller Instance</h2>
<p>After the release process, the environment will have a new automation manager, <code>DynamicTags_Manager</code>, and a new controller, <code>DynamicTags_Controller</code>.
To use it, just create a controller instance by connecting this controller to a Resource.</p>
<h2 id="installing-needed-software-for-testing">Installing needed software for testing:</h2>
<p>1 - Install the OPCUA Server (available on: <a href="https://criticalmfg.sharepoint.com/:f:/r/sites/ProductImplementation/Shared%20Documents/Connect%20IoT/Software/Simulator/OPC%20UA%20Server?csf=1&amp;web=1&amp;e=Eg9qqm" target="_blank" rel="noopener">OPC-UA Server</a>). After installation, start the UaCPPServer app and note the server address:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/uacppserver.png" alt="UaCPPServer" />

</p>
<p>2 - Install the OPCUA Client (available on: <a href="https://criticalmfg.sharepoint.com/:f:/r/sites/ProductImplementation/Shared%20Documents/Connect%20IoT/Software/Simulator/OPC%20UA%20Client?csf=1&amp;web=1&amp;e=JCuco6" target="_blank" rel="noopener">OPC-UA Client</a>). Start the OPCUA client and establish a connection to the server. Use the address supplied by the server app as the Endpoint Url:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/opcuaclient.png" alt="UaExpert" />

</p>
<p>3 - Open the <code>Objects</code> folder and drag the <code>AirConditioner_2</code> to the <code>DataAccessView</code> windows. Check the first node value is constantly changing (there is a simulation running in background). Later we will use the DynamicTags Controller to collect this data.

<img src="/blogPosts/IoT/20240521_iot_dynamictags/opendataaccessview.png" alt="UaExpertDataAccess" />

</p>
<h2 id="execution-time">Execution time!</h2>
<p>Use the OPCUA server address to configure the IoTMetadataDefinitions (for now, we just need these entries):

<img src="/blogPosts/IoT/20240521_iot_dynamictags/iotmetadataserver.png" alt="IoTMetadataServer" />

</p>
<p>Download the manager from MES GUI:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/downloadmanager.png" alt="Download manager" />

</p>
<p>Unzip it to a folder. Configure the correct paths in your config.json file to match your local needs (Cache, Persistency, IoT Repository and Logging):

<img src="/blogPosts/IoT/20240521_iot_dynamictags/managerconfigjson.png" alt="Run It" />

</p>
<p>Now run it:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/runstartconsole.png" alt="Run It" />

</p>
<p>If everything is ok, the controller should change state to &ldquo;Communicating&rdquo;:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/controllercommunicating.png" alt="Communicating" />

</p>
<h2 id="datacollection-perform-example">DataCollection Perform Example</h2>
<h3 id="fixed-time-intervals">Fixed time intervals:</h3>
<p>Let&rsquo;s setup the Controller to collect the Humidity data available at Tag <code>ns=3;s=AirConditioner_2.Humidity</code> referenced early.
Set CustomIoTOPCUADataCollectionContext as indicated:</p>
<p><strong>Tag:</strong> ns=3;s=AirConditioner_2.Humidity<br>
<strong>DataType:</strong> Decimal<br>
<strong>DeviceType:</strong> Double<br>
<strong>Event:</strong> CycleParametersEventType<br>
<strong>DataCollection:</strong> The DataCollection to be performed (<em>DynamicTagsTestDC</em> for this example)<br>
<strong>Parameter:</strong> The DataCollection Parameter to be performed  ( <em>DynamicTagsTestParam_1</em> for this example)<br>
<strong>CronExpression:</strong> The Cron Expression time to collect the data periodically at fixed times, dates or intervals. For this example let&rsquo;s use <code>*/10 * * * * *</code> to allow for a 10 seconds period<br>
<strong>CollectionMode:</strong> Perform To Resource</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuadatacollectioncontext_ex.png" alt="DataCollectionExample" />

</p>
<p>Restart the Controller, it should connect to the server and start collecting data. If we analyze the logs, we can find the moment when the data is about to be saved:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/dcintervalcontrollerlog.png" alt="DCControllerLogExample" />


<em>PS: Note the 10 second interval between collection timestamps</em></p>
<p>Also, if we query MES for that DataCollection, we should get the collected points:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/dcintervalquery.png" alt="DCIntervalQueryExample" />

</p>
<h3 id="triggered-by-value-changed">Triggered by value changed:</h3>
<p>If we are interested on collecting the data only when it&rsquo;s changing, just change this entries at CustomIoTOPCUADataCollectionContext:<br>
<strong>CronExpression:</strong> (empty)<br>
<strong>CycleCounter:</strong> 1<br>
<strong>IsTrigger:</strong> True</p>
<p>Restart the controller, and wait the Communication status going to Communicating. After some seconds, we should have a lot of collection points:<br>

<img src="/blogPosts/IoT/20240521_iot_dynamictags/dcintervalcontrollerlog_tagchange.png" alt="DCControllerLogExampleTagChg" />


Note now the timestamps. Each time the Tag ns=3;s=AirConditioner_2.Humidity change it&rsquo;s value, a datacollection is performed.</p>
<h2 id="machine-state-change-example">Machine State Change Example</h2>
<p>Let&rsquo;s setup now the Controller to collect the equipment State, represented by the Tag <code>ns=3;s=AirConditioner_3.State</code> (check the OPCUA client DataAccessView position #4)
Set CustomIoTOPCUADataCollectionContext as indicated:</p>
<p><strong>Tag:</strong> ns=3;s=AirConditioner_2.State<br>
<strong>DataType:</strong> Integer<br>
<strong>DeviceType:</strong> Int32<br>
<strong>Event:</strong> CycleParametersEventType<br>
<strong>DataCollection:</strong> (empty)<br>
<strong>Parameter:</strong> (empty)<br>
<strong>IsState, IsTrigger:</strong> True<br>
<strong>IsShot:</strong> False<br>
<strong>Interval:</strong> (empty)<br>
<strong>CollectionMode:</strong> Perform To Resource</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuamachinestate.png" alt="MachineStateExample" />

</p>
<p>In order to translate the Tag values to SEMI E10 states, we need also to setup the table IoTStateModelContext, for that resource. Since the Tag only takes &lsquo;0&rsquo; (Off) and &lsquo;1&rsquo; (On) as values, we only need to map these two values:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/iotstatemodelmachinestate.png" alt="MachineStateExample" />

</p>
<p>Now, restart the Controller so it can assume the new configurations.
In order to change the Tag value, since this server is running a simulation, we cannot change directly the value. Instead, we should send a <em>Start</em> or a <em>Stop</em> command. Let&rsquo;s send a <em>Stop</em> command:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/stopsimulation.png" alt="StopSimulation" />

</p>
<p>You should see now the Tag ns=3;s=AirConditioner_2.State now changed to &lsquo;0 (Off)&rsquo;.
Now, start again the simulation (just repeat the process above, this time for the <em>Start</em> command).
The tag should change now back to &lsquo;1 (On)&rsquo; value.
Looking at the controller logs, we can find both state changes:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/machinestatecontrollerlogs.png" alt="MachineStateLogs" />

</p>
<p>You can also check the Resource history at MES and find the state changes according:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/machinestatehistory.png" alt="MachineStateHistory" />

</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/machinestatehistoryback.png" alt="MachineStateHistoryBack" />

</p>
<h2 id="service-and-dee-calls-example">Service and DEE Calls Example</h2>
<p>The services and DEE calls are defined at smart table CustomIoTOPCUAExecutionContext.
Let&rsquo;s assume we want to call a DEE anytime the value of the Tag <em>ns=3;s=AirConditioner_2.TemperatureSetPoint</em> is changed.
Set CustomIoTOPCUAExecutionContext as indicated:</p>
<p><strong>Tag:</strong> ns=3;s=AirConditioner_2.TemperatureSetPoint<br>
<strong>DataType:</strong> Decimal<br>
<strong>DeviceType:</strong> Double<br>
<strong>Event:</strong> Execution<br>
<strong>ExecDee:</strong> True<br>
<strong>ExecService:</strong> False<br>
<strong>ExecDefinition:</strong> Name of the DEE to be executed (<em>CustomIoTSetPointChanged</em> for this example)<br>
<strong>TriggerOnChange:</strong> True</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuadeeexample.png" alt="DEECallExample" />

</p>
<p>Now, restart the Controller so it can assume the new configurations. Change the Tag value (double-click at the value):</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/setpointchange.png" alt="SetPointChangeExample" />

</p>
<p>We should find at Controller logs the entries related to this DEE call:</p>
<p>
<img src="/blogPosts/IoT/20240521_iot_dynamictags/deecontrollercall.png" alt="DEECallLogs" />

</p>
<p>For a service call example, follow the same procedure. Just change the <em>ExecDee</em> and <em>ExecService</em> according and use the service namespace and url at <em>ExecDefinition</em>, separated by a pipe ( &ldquo;|&rdquo; ):</p>
<p><strong>ExecDee:</strong> False<br>
<strong>ExecService:</strong> True<br>
<strong>ExecDefinition:</strong> Cmf.Foundation.BusinessOrchestration.ApplicationMonitoringManagement.InputObjects.SetMaintenanceModeInput, Cmf.Foundation.BusinessOrchestration|api/ApplicationMonitoring/SetPointChangedService</p>
<h2 id="recipe-management-examples">Recipe Management Examples</h2>
<h3 id="get-recipe-body">Get Recipe Body</h3>
<p>Let&rsquo;as assume our equipment has two main setpoints, Temperature and Humidity, for a specified equipment recipe (in this example, <em>TestRecipeForProduct_1</em>):

<img src="/blogPosts/IoT/20240521_iot_dynamictags/opcuaclientsetpoints.png" alt="EquipmentsSetPoints" />

</p>
<p>We should set the smart table CustomIoTOPCUARecipeContext according:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/customiotopcuarecipecontext_ex.png" alt="CustomIoTOPCUARecipeContextBodyEx" />

</p>
<p>Now, create a new Recipe <code>TestRecipe</code> at MES (or create a new version if already exist), be sure to set the <code>Resource Recipe Name</code> the same you already set at CustomIoTOPCUARecipeContext table:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/createnewrecipe.png" alt="CreateNewRecipe" />

</p>
<p>Go to Recipe Details &gt; Body &gt; Manage:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/recipemanagebody.png" alt="RecipeBodyManage" />

</p>
<p>Select <code>Downloaded From Equipment</code> as the Source, set the Resource and click  <code>GetRecipes</code>. The Controller will reply back with all Recipes existing at CustomIoTOPCUARecipeContext for this Resource:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/recipemanagebody_combo.png" alt="RecipeBodyManageCombo" />

</p>
<p>Pick the <code>TestRecipeForProduct_1</code> and then click  <code>Download Body</code>. The Controller will get the setpoints (Tags) from the equipment and send them as the body to MES:<br>

<img src="/blogPosts/IoT/20240521_iot_dynamictags/recipedownloadedbody.png" alt="RecipeDownloadedBody" />

</p>
<p>We can verify the body content. Just download the body and check it&rsquo;s contents against the equipment setpoints indicated previously (Humidity: 60, Temperature: 72):<br>

<img src="/blogPosts/IoT/20240521_iot_dynamictags/bodycontents.png" alt="BodyContents" />

</p>
<p><em>PS: In the DynamicTags&rsquo;s implementation, the Recipe Body is used to save Parameters data (tag names, definitions and values)</em>. <em>This is not saved in the Recipe Parameters as expected</em>.</p>
<h3 id="set-recipe">Set Recipe</h3>
<p>Now we have the setpoints already store at the Recipe, we can set these setpoints back to the equipment when needed.<br>
First, let&rsquo;s change our current setpoints to any other different values: Humidity: 59, Temperature: 71. (At OPCUA client, just double-click the value and enters a new value):

<img src="/blogPosts/IoT/20240521_iot_dynamictags/opcuaclientchangedsetpoints.png" alt="ChangedSetPoints" />

</p>
<p>Go to our Resource main page, and click <code>Set</code>. Select the Recipe <code>TestRecipe</code> and click <code>Set</code>:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/setrecipe.png" alt="SetRecipe" />

</p>
<p>The Controller will receive a request from MES with the Recipe body data and will send the new setpoints to the equipment:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/controllernewsetpoints.png" alt="ControllerNewSetpoints" />

</p>
<p>Now the equipment received the new setpoints corresponding to this Recipe:

<img src="/blogPosts/IoT/20240521_iot_dynamictags/opcuaclientnewsetpoints.png" alt="NewSetPoints" />

</p>
<p><br></br></p>
<hr>
<p><br></br></p>
<h2 id="author">Author</h2>
<p>Hello, my name is Luis Filipe Mascarenhas
I am an IoT Engineer for the SMT area.
You can visit me at <a href="https://www.linkedin.com/in/luis-filipe-mascarenhas-2bb4b878" target="_blank" rel="noopener">LinkedIn</a></p>
<p>Skills: Connect IoT

<figure class="text-center">
  <img
    src="/blogPosts/contributors/blogger_luis_mascarenhas.jpg"
    alt="Luis Filipe Mascarenhas"
    title="IoT Engineer"
  />
  <figcaption style="text-align: center">IoT Engineer</figcaption>
</figure>

</p>
]]></content:encoded></item></channel></rss>