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

Difference between revisions of "BaSyx / Introductory Examples / Java / Example 4"

m (Updates example to not use deprecated API & to use AASLambdaPropertyHelper)
m (Example Code)
Line 44: Line 44:
 
* Sensor Submodel
 
* Sensor Submodel
 
*/
 
*/
SubModel sensorSubModel = new SubModel("Sensor", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
+
Submodel sensorSubModel = new Submodel("Sensor", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
 
// Create a lambda property containing the current sensor temperature
 
// Create a lambda property containing the current sensor temperature
Property temperatureProperty = new Property("currentTemperature", PropertyValueTypeDef.Double);
+
Property temperatureProperty = new Property("currentTemperature", ValueType.Double);
 
AASLambdaPropertyHelper.setLambdaValue(temperatureProperty, () -> {
 
AASLambdaPropertyHelper.setLambdaValue(temperatureProperty, () -> {
 
return myOven.getSensor().readTemperature();
 
return myOven.getSensor().readTemperature();
 
}, null);
 
}, null);
 
+
 
// Adds a reference to a semantic ID to specify the property semantics (see eCl@ss)
 
// Adds a reference to a semantic ID to specify the property semantics (see eCl@ss)
temperatureProperty.setSemanticID(
+
temperatureProperty.setSemanticId(
 
new Reference(new Key(KeyElements.PROPERTY, false, "0173-1#02-AAV232#002", KeyType.IRDI)));
 
new Reference(new Key(KeyElements.PROPERTY, false, "0173-1#02-AAV232#002", KeyType.IRDI)));
sensorSubModel.addSubModelElement(temperatureProperty);
+
sensorSubModel.addSubmodelElement(temperatureProperty);
 
   
 
   
Property temperatureUnit = new Property("temperatureUnit", PropertyValueTypeDef.String);
+
Property temperatureUnit = new Property("temperatureUnit", ValueType.String);
temperatureUnit.set("Celsius");
+
temperatureUnit.setValue("Celsius");
sensorSubModel.addSubModelElement(temperatureUnit);
+
sensorSubModel.addSubmodelElement(temperatureUnit);
 
   
 
   
 
/**
 
/**
 
* Control Submodel
 
* Control Submodel
 
*/
 
*/
SubModel heaterSubModel = new SubModel("Control", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
+
Submodel heaterSubModel = new Submodel("Control", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
 
// Create an operation that uses the control component to set a temperature value
 
// Create an operation that uses the control component to set a temperature value
 
Function<Object[], Object> heatInvokable = (params) -> {
 
Function<Object[], Object> heatInvokable = (params) -> {
Line 71: Line 71:
 
   
 
   
 
// Select the operation from the control component
 
// Select the operation from the control component
proxy.setModelPropertyValue("status/opMode", OvenControlComponent.OPMODE_HEAT);
+
proxy.setValue("status/opMode", OvenControlComponent.OPMODE_HEAT);
 
   
 
   
 
// Start the control component operation asynchronous
 
// Start the control component operation asynchronous
Line 77: Line 77:
 
   
 
   
 
// Wait until the operation is completed
 
// Wait until the operation is completed
while (!proxy.getModelPropertyValue("status/exState").equals(ExecutionState.COMPLETE.getValue())) {
+
while (!proxy.getValue("status/exState").equals(ExecutionState.COMPLETE.getValue())) {
 
try {
 
try {
 
Thread.sleep(500);
 
Thread.sleep(500);
Line 91: Line 91:
 
// Create the Operation
 
// Create the Operation
 
Operation operation = new Operation("setTemperature");
 
Operation operation = new Operation("setTemperature");
operation.setInvocable(heatInvokable);
+
operation.setInvokable(heatInvokable);
heaterSubModel.addSubModelElement(operation);
+
heaterSubModel.addSubmodelElement(operation);
 
   
 
   
 
/**
 
/**
 
* Minimal AAS Information
 
* Minimal AAS Information
 
*/
 
*/
 
+
 
Asset asset = new Asset("ovenAsset", new ModelUrn("urn:org.eclipse.basyx:OvenAsset"), AssetKind.INSTANCE);
 
Asset asset = new Asset("ovenAsset", new ModelUrn("urn:org.eclipse.basyx:OvenAsset"), AssetKind.INSTANCE);
 
+
 
ModelUrn aasURN = new ModelUrn("urn:org.eclipse.basyx:OvenAAS");
 
ModelUrn aasURN = new ModelUrn("urn:org.eclipse.basyx:OvenAAS");
 
AssetAdministrationShell aas = new AssetAdministrationShell("oven", aasURN, asset);
 
AssetAdministrationShell aas = new AssetAdministrationShell("oven", aasURN, asset);
Line 112: Line 112:
 
// AASModelProvider and SubModelProvider implement the IModelProvider interface
 
// AASModelProvider and SubModelProvider implement the IModelProvider interface
 
AASModelProvider aasProvider = new AASModelProvider(aas);
 
AASModelProvider aasProvider = new AASModelProvider(aas);
SubModelProvider sensorSMProvider = new SubModelProvider(sensorSubModel);
+
SubmodelProvider sensorSMProvider = new SubmodelProvider(sensorSubModel);
SubModelProvider heaterSMProvider = new SubModelProvider(heaterSubModel);
+
SubmodelProvider heaterSMProvider = new SubmodelProvider(heaterSubModel);
 
   
 
   
 
// Add the independent providers to the MultiSubmodelProvider that can be deployed on a single node
 
// Add the independent providers to the MultiSubmodelProvider that can be deployed on a single node
VABMultiSubmodelProvider fullProvider = new VABMultiSubmodelProvider();
+
MultiSubmodelProvider fullProvider = new MultiSubmodelProvider();
 
fullProvider.setAssetAdministrationShell(aasProvider);
 
fullProvider.setAssetAdministrationShell(aasProvider);
 
fullProvider.addSubmodel(sensorSMProvider);
 
fullProvider.addSubmodel(sensorSMProvider);
Line 132: Line 132:
 
   
 
   
 
// For this HandsOn, create an InMemoryRegistry for registering the AAS
 
// For this HandsOn, create an InMemoryRegistry for registering the AAS
IAASRegistryService registry = new InMemoryRegistry();
+
IAASRegistry registry = new InMemoryRegistry();
IModelProvider registryProvider = new DirectoryModelProvider(registry);
+
IModelProvider registryProvider = new AASRegistryModelProvider(registry);
 
HttpServlet registryServlet = new VABHTTPInterface<IModelProvider>(registryProvider);
 
HttpServlet registryServlet = new VABHTTPInterface<IModelProvider>(registryProvider);
 
   
 
   
 
// now add the references of the submodels to the AAS header
 
// now add the references of the submodels to the AAS header
aas.addSubModel(sensorSubModel);
+
aas.addSubmodel(sensorSubModel);
aas.addSubModel(heaterSubModel);
+
aas.addSubmodel(heaterSubModel);
 
   
 
   
 
// Register the VAB model at the directory (locally in this case)
 
// Register the VAB model at the directory (locally in this case)
Line 153: Line 153:
 
context.addServletMapping("/oven/*", aasServlet);
 
context.addServletMapping("/oven/*", aasServlet);
 
context.addServletMapping("/registry/*", registryServlet);
 
context.addServletMapping("/registry/*", registryServlet);
AASHTTPServer httpServer = new AASHTTPServer(context);
+
BaSyxHTTPServer httpServer = new BaSyxHTTPServer(context);
 
   
 
   
 
   
 
   

Revision as of 20:40, 8 March 2021

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.

/** 
 * Now we actually create an oven AssetAdministrationShell (AAS) using the standardized metamodel
 * 
 * The AAS will have two simple submodels:
 * Sensor
 * - submodel that represents the temperature sensor of the oven
 * Control
 * - submodel for accessing the connected control component via the AAS API
 * 
 * 
 * Expected output:
 * - the Asset Administration Shell for the oven device is accessible using the internet browser (because of the
 * HTTP-REST interface that is used in this HandsOn)
 * - the Registry is accessible using the internet browser (because of the
 * HTTP-REST interface that is used in this HandsOn)
 */
public class Scenario4 {
	public static void main(String[] args) throws Exception {
		// Create and provide the control component from the previous HandsOn
		Oven myOven = new Oven();
		Scenario3.startMyControlComponent(myOven);
		startMyAssetAdministrationShell(myOven);
	}
 
	public static void startMyAssetAdministrationShell(Oven myOven) {
		/**
		 * Sensor Submodel
		 */
		Submodel sensorSubModel = new Submodel("Sensor", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
		// Create a lambda property containing the current sensor temperature
		Property temperatureProperty = new Property("currentTemperature", ValueType.Double);
		AASLambdaPropertyHelper.setLambdaValue(temperatureProperty, () -> {
			return myOven.getSensor().readTemperature();
		}, null);
 
		// Adds a reference to a semantic ID to specify the property semantics (see eCl@ss)
		temperatureProperty.setSemanticId(
				new Reference(new Key(KeyElements.PROPERTY, false, "0173-1#02-AAV232#002", KeyType.IRDI)));
		sensorSubModel.addSubmodelElement(temperatureProperty);
 
		Property temperatureUnit = new Property("temperatureUnit", ValueType.String);
		temperatureUnit.setValue("Celsius");
		sensorSubModel.addSubmodelElement(temperatureUnit);
 
		/**
		 * Control Submodel
		 */
		Submodel heaterSubModel = new Submodel("Control", new ModelUrn("urn:org.eclipse.basyx:SensorSubmodel"));
		// Create an operation that uses the control component to set a temperature value
		Function<Object[], Object> heatInvokable = (params) -> {
			// From: HandsOn 04
			// Connect to the control component
			VABElementProxy proxy = new VABElementProxy("", new JSONConnector(new BaSyxConnector("localhost", 4002)));
 
			// Select the operation from the control component
			proxy.setValue("status/opMode", OvenControlComponent.OPMODE_HEAT);
 
			// Start the control component operation asynchronous
			proxy.invokeOperation("/operations/service/start");
 
			// Wait until the operation is completed
			while (!proxy.getValue("status/exState").equals(ExecutionState.COMPLETE.getValue())) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
				}
			}
 
			proxy.invokeOperation("operations/service/reset");
			// Then return -> synchronous
			return null;
		};
 
		// Create the Operation
		Operation operation = new Operation("setTemperature");
		operation.setInvokable(heatInvokable);
		heaterSubModel.addSubmodelElement(operation);
 
		/**
		 * Minimal AAS Information
		 */
 
		Asset asset = new Asset("ovenAsset", new ModelUrn("urn:org.eclipse.basyx:OvenAsset"), AssetKind.INSTANCE);
 
		ModelUrn aasURN = new ModelUrn("urn:org.eclipse.basyx:OvenAAS");
		AssetAdministrationShell aas = new AssetAdministrationShell("oven", aasURN, asset);
		// Note: The submodels are not directly integrated into the AAS model. This makes it possible to distribute
		// submodels to different nodes
		// The header contains references to the previously created submodels.
		// Here, the submodel endpoints are not yet known. They can be specified as soon as the real endpoints are known
 
		/**
		 * Again: Wrap the model in an IModelProvider (now specific to the AAS and submodel)
		 */
		// AASModelProvider and SubModelProvider implement the IModelProvider interface
		AASModelProvider aasProvider = new AASModelProvider(aas);
		SubmodelProvider sensorSMProvider = new SubmodelProvider(sensorSubModel);
		SubmodelProvider heaterSMProvider = new SubmodelProvider(heaterSubModel);
 
		// Add the independent providers to the MultiSubmodelProvider that can be deployed on a single node
		MultiSubmodelProvider fullProvider = new MultiSubmodelProvider();
		fullProvider.setAssetAdministrationShell(aasProvider);
		fullProvider.addSubmodel(sensorSMProvider);
		fullProvider.addSubmodel(heaterSMProvider);
 
		// Although the providers for aas/submodels implement the AAS API, they are still IModelProviders!
		// IModelProvider aasIModelProvider = fullProvider;
 
		/**
		 * Deployment
		 */
		// Now, the IModelProvider is given to a HTTP servlet that gives access to the model in the next steps
		// => The model will be published using an HTTP-REST interface
		HttpServlet aasServlet = new VABHTTPInterface<IModelProvider>(fullProvider);
 
		// For this HandsOn, create an InMemoryRegistry for registering the AAS
		IAASRegistry registry = new InMemoryRegistry();
		IModelProvider registryProvider = new AASRegistryModelProvider(registry);
		HttpServlet registryServlet = new VABHTTPInterface<IModelProvider>(registryProvider);
 
		// now add the references of the submodels to the AAS header
		aas.addSubmodel(sensorSubModel);
		aas.addSubmodel(heaterSubModel);
 
		// Register the VAB model at the directory (locally in this case)
		AASDescriptor aasDescriptor = new AASDescriptor(aas, "http://localhost:4000/handson/oven/aas");
		// Explicitly create and add submodel descriptors
		SubmodelDescriptor sensorSMDescriptor = new SubmodelDescriptor(sensorSubModel, "http://localhost:4000/handson/oven/aas/submodels/Sensor");
		SubmodelDescriptor heaterSMDescriptor = new SubmodelDescriptor(heaterSubModel, "http://localhost:4000/handson/oven/aas/submodels/Control");
		aasDescriptor.addSubmodelDescriptor(sensorSMDescriptor);
		aasDescriptor.addSubmodelDescriptor(heaterSMDescriptor);
		registry.register(aasDescriptor);
 
		// Deploy the AAS on a HTTP server
		BaSyxContext context = new BaSyxContext("/handson", "", "localhost", 4000);
		context.addServletMapping("/oven/*", aasServlet);
		context.addServletMapping("/registry/*", registryServlet);
		BaSyxHTTPServer httpServer = new BaSyxHTTPServer(context);
 
 
		httpServer.start();
 
		// Now in the browser, look at the various endpoints to see what is returned:
		// - AAS: http://localhost:4000/handson/oven/aas/
		// - Sensor Submodel: http://localhost:4000/handson/oven/aas/submodels/Sensor/
		// - Control Submodel: http://localhost:4000/handson/oven/aas/submodels/Control/
 
		// Similar, the registry also has a HTTP-REST interface. So, it is possible to directly query it:
		// - Show all AAS: http://localhost:4000/handson/registry/api/v1/registry/
		// - Show my AAS: http://localhost:4000/handson/registry/api/v1/registry/urn:org.eclipse.basyx:OvenAAS
		// Note: the "#" character in the URN s encoded as "%23"
 
		// The server can also be shut down:
		/* 
		try {
			// Wait for 5s and then shutdown the server
			Thread.sleep(5000);
			httpServer.shutdown();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		*/
	}
}

Back to the top