Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

BaSyx / Introductory Examples / Java / Example 4

< BaSyx ‎ | Introductory Examples
Revision as of 10:02, 23 August 2021 by Rene-pascal.fischer.iese.fraunhofer.de (Talk | contribs) (Adds line numbers and expected output)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Example 4

After the last example, we can control the oven through a unified service interface. However, the provided descriptions, data and semantics are still custom made. Thus, an application working with the oven, retrieving temperature and controlling it is not necessary interoperable with another oven, using the same abstract data but not the same model.

To fill this gap, the Asset Administration Shell will be used in this example. Additionally, we will explore the AAS meta model through its HTTP-Rest interface by using any browser.

Example Code

First, two submodels are created with properties and operations. These properties/operations hold meta data giving a description of their semantics. The defined submodels are:

  1. SensorSubModel: Contains sensor data, in this case the temperature value. Additionally, a temperature unit is made available.
  2. ControlSubModel: Exposes the services available, in this case it references the Control Component.


Please note that the Control Component is a concept not within the standard of the AAS. Thus, the Control Component has to be either referenced like in this example or expose itself through the submodel interface. Additionally, the standard referenced by the temperature property already defines the unit. For the sake of this tutorial, it is assumed that the oven is not 100% conforming to this standard and can switch between Fahrenheit and Celsius.

Next, these submodels are added to an AAS and hosted via HTTP. Additionally, the AAS and its submodel are registered with the AAS Registry. After starting the HTTP server and registering, the Registry, AAS and its submodel can be explored via the HTTP-REST interface as described in the example or above.

  1. import java.util.function.Function;
  2.  
  3. import javax.servlet.http.HttpServlet;
  4.  
  5. import org.eclipse.basyx.aas.metamodel.api.parts.asset.AssetKind;
  6. import org.eclipse.basyx.aas.metamodel.map.AssetAdministrationShell;
  7. import org.eclipse.basyx.aas.metamodel.map.descriptor.AASDescriptor;
  8. import org.eclipse.basyx.aas.metamodel.map.descriptor.ModelUrn;
  9. import org.eclipse.basyx.aas.metamodel.map.descriptor.SubmodelDescriptor;
  10. import org.eclipse.basyx.aas.metamodel.map.parts.Asset;
  11. import org.eclipse.basyx.aas.registration.api.IAASRegistry;
  12. import org.eclipse.basyx.aas.registration.memory.InMemoryRegistry;
  13. import org.eclipse.basyx.aas.registration.restapi.AASRegistryModelProvider;
  14. import org.eclipse.basyx.aas.restapi.AASModelProvider;
  15. import org.eclipse.basyx.aas.restapi.MultiSubmodelProvider;
  16. import org.eclipse.basyx.models.controlcomponent.ExecutionState;
  17. import org.eclipse.basyx.submodel.metamodel.api.reference.enums.KeyElements;
  18. import org.eclipse.basyx.submodel.metamodel.api.reference.enums.KeyType;
  19. import org.eclipse.basyx.submodel.metamodel.map.Submodel;
  20. import org.eclipse.basyx.submodel.metamodel.map.reference.Key;
  21. import org.eclipse.basyx.submodel.metamodel.map.reference.Reference;
  22. import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.AASLambdaPropertyHelper;
  23. import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.Property;
  24. import org.eclipse.basyx.submodel.metamodel.map.submodelelement.dataelement.property.valuetype.ValueType;
  25. import org.eclipse.basyx.submodel.metamodel.map.submodelelement.operation.Operation;
  26. import org.eclipse.basyx.submodel.restapi.SubmodelProvider;
  27. import org.eclipse.basyx.vab.coder.json.connector.JSONConnector;
  28. import org.eclipse.basyx.vab.modelprovider.VABElementProxy;
  29. import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
  30. import org.eclipse.basyx.vab.protocol.basyx.connector.BaSyxConnector;
  31. import org.eclipse.basyx.vab.protocol.http.server.BaSyxContext;
  32. import org.eclipse.basyx.vab.protocol.http.server.BaSyxHTTPServer;
  33. import org.eclipse.basyx.vab.protocol.http.server.VABHTTPInterface;
  34.  
  35. /** 
  36.  * Now we actually create an oven AssetAdministrationShell (AAS) using the standardized metamodel
  37.  * 
  38.  * The AAS will have two simple submodels:
  39.  * Sensor
  40.  * - submodel that represents the temperature sensor of the oven
  41.  * Control
  42.  * - submodel for accessing the connected control component via the AAS API
  43.  * 
  44.  * 
  45.  * Expected output:
  46.  * - the Asset Administration Shell for the oven device is accessible using the internet browser (because of the
  47.  * HTTP-REST interface that is used in this HandsOn)
  48.  * - the Registry is accessible using the internet browser (because of the
  49.  * HTTP-REST interface that is used in this HandsOn)
  50.  */
  51. public class Scenario4 {
  52. 	public static void main(String[] args) throws Exception {
  53. 		// Create and provide the control component from the previous HandsOn
  54. 		Oven myOven = new Oven();
  55. 		Scenario3.startMyControlComponent(myOven);
  56. 		startMyAssetAdministrationShell(myOven);
  57. 	}
  58.  
  59. 	public static void startMyAssetAdministrationShell(Oven myOven) {
  60. 		/**
  61. 		 * Sensor Submodel
  62. 		 */
  63. 		Submodel sensorSubModel = new Submodel("Sensor", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
  64. 		// Create a lambda property containing the current sensor temperature
  65. 		Property temperatureProperty = new Property("currentTemperature", ValueType.Double);
  66. 		AASLambdaPropertyHelper.setLambdaValue(temperatureProperty, () -> {
  67. 			return myOven.getSensor().readTemperature();
  68. 		}, null);
  69.  
  70. 		// Adds a reference to a semantic ID to specify the property semantics (see eCl@ss)
  71. 		temperatureProperty.setSemanticId(
  72. 				new Reference(new Key(KeyElements.PROPERTY, false, "0173-1#02-AAV232#002", KeyType.IRDI)));
  73. 		sensorSubModel.addSubmodelElement(temperatureProperty);
  74.  
  75. 		Property temperatureUnit = new Property("temperatureUnit", ValueType.String);
  76. 		temperatureUnit.setValue("Celsius");
  77. 		sensorSubModel.addSubmodelElement(temperatureUnit);
  78.  
  79. 		/**
  80. 		 * Control Submodel
  81. 		 */
  82. 		Submodel heaterSubModel = new Submodel("Control", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
  83. 		// Create an operation that uses the control component to set a temperature value
  84. 		Function<Object[], Object> heatInvokable = (params) -> {
  85. 			// From: HandsOn 04
  86. 			// Connect to the control component
  87. 			VABElementProxy proxy = new VABElementProxy("", new JSONConnector(new BaSyxConnector("localhost", 4002)));
  88.  
  89. 			// Select the operation from the control component
  90. 			proxy.setValue("status/opMode", OvenControlComponent.OPMODE_HEAT);
  91.  
  92. 			// Start the control component operation asynchronous
  93. 			proxy.invokeOperation("/operations/service/start");
  94.  
  95. 			// Wait until the operation is completed
  96. 			while (!proxy.getValue("status/exState").equals(ExecutionState.COMPLETE.getValue())) {
  97. 				try {
  98. 					Thread.sleep(500);
  99. 				} catch (InterruptedException e) {
  100. 				}
  101. 			}
  102.  
  103. 			proxy.invokeOperation("operations/service/reset");
  104. 			// Then return -> synchronous
  105. 			return null;
  106. 		};
  107.  
  108. 		// Create the Operation
  109. 		Operation operation = new Operation("setTemperature");
  110. 		operation.setInvokable(heatInvokable);
  111. 		heaterSubModel.addSubmodelElement(operation);
  112.  
  113. 		/**
  114. 		 * Minimal AAS Information
  115. 		 */
  116.  
  117. 		Asset asset = new Asset("ovenAsset", new ModelUrn("urn:org.eclipse.basyx:OvenAsset"), AssetKind.INSTANCE);
  118.  
  119. 		ModelUrn aasURN = new ModelUrn("urn:org.eclipse.basyx:OvenAAS");
  120. 		AssetAdministrationShell aas = new AssetAdministrationShell("oven", aasURN, asset);
  121. 		// Note: The submodels are not directly integrated into the AAS model. This makes it possible to distribute
  122. 		// submodels to different nodes
  123. 		// The header contains references to the previously created submodels.
  124. 		// Here, the submodel endpoints are not yet known. They can be specified as soon as the real endpoints are known
  125.  
  126. 		/**
  127. 		 * Again: Wrap the model in an IModelProvider (now specific to the AAS and submodel)
  128. 		 */
  129. 		// AASModelProvider and SubModelProvider implement the IModelProvider interface
  130. 		AASModelProvider aasProvider = new AASModelProvider(aas);
  131. 		SubmodelProvider sensorSMProvider = new SubmodelProvider(sensorSubModel);
  132. 		SubmodelProvider heaterSMProvider = new SubmodelProvider(heaterSubModel);
  133.  
  134. 		// Add the independent providers to the MultiSubmodelProvider that can be deployed on a single node
  135. 		MultiSubmodelProvider fullProvider = new MultiSubmodelProvider();
  136. 		fullProvider.setAssetAdministrationShell(aasProvider);
  137. 		fullProvider.addSubmodel(sensorSMProvider);
  138. 		fullProvider.addSubmodel(heaterSMProvider);
  139.  
  140. 		// Although the providers for aas/submodels implement the AAS API, they are still IModelProviders!
  141. 		// IModelProvider aasIModelProvider = fullProvider;
  142.  
  143. 		/**
  144. 		 * Deployment
  145. 		 */
  146. 		// Now, the IModelProvider is given to a HTTP servlet that gives access to the model in the next steps
  147. 		// => The model will be published using an HTTP-REST interface
  148. 		HttpServlet aasServlet = new VABHTTPInterface<IModelProvider>(fullProvider);
  149.  
  150. 		// For this HandsOn, create an InMemoryRegistry for registering the AAS
  151. 		IAASRegistry registry = new InMemoryRegistry();
  152. 		IModelProvider registryProvider = new AASRegistryModelProvider(registry);
  153. 		HttpServlet registryServlet = new VABHTTPInterface<IModelProvider>(registryProvider);
  154.  
  155. 		// now add the references of the submodels to the AAS header
  156. 		aas.addSubmodel(sensorSubModel);
  157. 		aas.addSubmodel(heaterSubModel);
  158.  
  159. 		// Register the VAB model at the directory (locally in this case)
  160. 		AASDescriptor aasDescriptor = new AASDescriptor(aas, "http://localhost:4000/handson/oven/aas");
  161. 		// Explicitly create and add submodel descriptors
  162. 		SubmodelDescriptor sensorSMDescriptor = new SubmodelDescriptor(sensorSubModel, "http://localhost:4000/handson/oven/aas/submodels/Sensor");
  163. 		SubmodelDescriptor heaterSMDescriptor = new SubmodelDescriptor(heaterSubModel, "http://localhost:4000/handson/oven/aas/submodels/Control");
  164. 		aasDescriptor.addSubmodelDescriptor(sensorSMDescriptor);
  165. 		aasDescriptor.addSubmodelDescriptor(heaterSMDescriptor);
  166. 		registry.register(aasDescriptor);
  167.  
  168. 		// Deploy the AAS on a HTTP server
  169. 		BaSyxContext context = new BaSyxContext("/handson", "", "localhost", 4000);
  170. 		context.addServletMapping("/oven/*", aasServlet);
  171. 		context.addServletMapping("/registry/*", registryServlet);
  172. 		BaSyxHTTPServer httpServer = new BaSyxHTTPServer(context);
  173.  
  174.  
  175. 		httpServer.start();
  176.  
  177. 		// Now in the browser, look at the various endpoints to see what is returned:
  178. 		// - AAS: http://localhost:4000/handson/oven/aas/
  179. 		// - Sensor Submodel: http://localhost:4000/handson/oven/aas/submodels/Sensor/
  180. 		// - Control Submodel: http://localhost:4000/handson/oven/aas/submodels/Control/
  181.  
  182. 		// Similar, the registry also has a HTTP-REST interface. So, it is possible to directly query it:
  183. 		// - Show all AAS: http://localhost:4000/handson/registry/api/v1/registry/
  184. 		// - Show my AAS: http://localhost:4000/handson/registry/api/v1/registry/urn:org.eclipse.basyx:OvenAAS
  185. 		// Note: the "#" character in the URN s encoded as "%23"
  186.  
  187. 		// The server can also be shut down:
  188. 		/* 
  189. 		try {
  190. 			// Wait for 5s and then shutdown the server
  191. 			Thread.sleep(5000);
  192. 			httpServer.shutdown();
  193. 		} catch (InterruptedException e) {
  194. 			e.printStackTrace();
  195. 		}
  196. 		*/
  197. 	}
  198. }


Expected Output

The output will consist of the info (maybe in a red text color) about the BaSyx Context and HTTP server (a Tomcat server) which has been started. No other output will be generated in the console. You have to visit [ http://localhost:4000/handson/oven/aas ] to check if everything works as expected and explore the AAS meta model through its HTTP-Rest interface.

Back to the top