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 (Adds explanation on "temperatureUnit" property)
m (Fixes Key initialization with the correct parameter)
Line 57: Line 57:
 
// 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(ReferableElements.Property, false, "0173-1#02-AAV232#002", "IRDI")));
+
new Reference(new Key(KeyElements.PROPERTY, false, "0173-1#02-AAV232#002", KeyType.IRDI)));
 
sensorSubModel.addSubModelElement(temperatureProperty);
 
sensorSubModel.addSubModelElement(temperatureProperty);
  

Revision as of 07:28, 2 March 2020

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();
		sensorSubModel.setIdShort("Sensor");
		// Create a lambda property containing the current sensor temperature
		Property temperatureProperty = new Property();
		temperatureProperty.setIdShort("currentTemperature");
		temperatureProperty.set(VABLambdaProviderHelper.createSimple(() -> {
			return myOven.getSensor().readTemperature();
		}, null));
		// For lambda properties, the type has to be explicitly specified as it can not be retrieved from the given
		// supplier automatically
		temperatureProperty.setValueType(PropertyValueTypeDef.Double);
		// 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("Fahrenheit");
		temperatureUnit.setIdShort("temperatureUnit");
		sensorSubModel.addSubModelElement(temperatureUnit);
 
		/**
		 * Control Submodel
		 */
		SubModel heaterSubModel = new SubModel();
		heaterSubModel.setIdShort("Control");
		// 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.setModelPropertyValue("status/opMode", OvenControlComponent.OPMODE_HEAT);
 
			// Start the control component operation asynchronous
			proxy.invokeOperation("/operations/service/start");
 
			// Wait until the operation is completed
			while (!proxy.getModelPropertyValue("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();
		operation.setIdShort("setTemperature");
		operation.setInvocable(heatInvokable);
		heaterSubModel.addSubModelElement(operation);
 
		/**
		 * Minimal AAS Information
		 */
		AssetAdministrationShell aas = new AssetAdministrationShell();
		// Add a unique Identification and a name (== short ID)
		ModelUrn aasURN = new ModelUrn("de.FHG", "devices.es.iese", "AAS", "1.0", "1", "oven01", "001");
		aas.setIdentification(aasURN);
		aas.setIdShort("oven");
		// 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
		VABMultiSubmodelProvider fullProvider = new VABMultiSubmodelProvider();
		fullProvider.setAssetAdministrationShell(aasProvider);
		fullProvider.addSubmodel("Sensor", sensorSMProvider);
		fullProvider.addSubmodel("Control", 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
		IAASRegistryService registry = new InMemoryRegistry();
		IModelProvider registryProvider = new DirectoryModelProvider(registry);
		HttpServlet registryServlet = new VABHTTPInterface<IModelProvider>(registryProvider);
 
		// now add the references of the submodels to the AAS header
		aas.addSubModel(new SubmodelDescriptor(sensorSubModel,
				"http://localhost:4000/handson/oven/aas/submodels/Sensor/submodel"));
		aas.addSubModel(new SubmodelDescriptor(heaterSubModel, "http://localhost:4000/handson/oven/aas/submodels/Control/submodel"));
 
		// Register the VAB model at the directory (locally in this case)
		AASDescriptor aasDescriptor = new AASDescriptor(aas, "http://localhost:4000/handson/oven/aas");
		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);
		AASHTTPServer httpServer = new AASHTTPServer(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:de.FHG:devices.es.iese:AAS:1.0:1:oven01%23001
		// 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