Skip to main content
Jump to: navigation, search

BaSyx / Introductory Examples / Java / Example 3

Example 3

Previously, Example 1 and 2 had set up the connection of the oven to the VAB. Through this connection, the oven is controllable regardless of location and protocol.

However, the service invocation is still custom made and may differ from oven to oven. Thus, an abstraction of service interface is needed. This is done by the Control Component.

In this example, a control component for the oven is created by extending the SimpleControlComponent class of the Components project.

Example Code

Again, the code is separated between local and remote code. First, the Control Component is set up. Please note, that in this tutorial it is not registered at the Registry. This is done to showcase how to connect to known entities on the VAB that for one reason or another are not registered.

First, in startMyControlComponent() the control component is created and hosted on a TCP server. Next, the code connects to the Control Component via direct address input and controls it via the Control Component VAB API mapping.

  1. import org.eclipse.basyx.models.controlcomponent.ControlComponent;
  2. import org.eclipse.basyx.models.controlcomponent.ExecutionState;
  3. import org.eclipse.basyx.vab.coder.json.connector.JSONConnector;
  4. import org.eclipse.basyx.vab.modelprovider.VABElementProxy;
  5. import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
  6. import org.eclipse.basyx.vab.modelprovider.map.VABMapProvider;
  7. import org.eclipse.basyx.vab.protocol.basyx.connector.BaSyxConnector;
  8. import org.eclipse.basyx.vab.protocol.basyx.server.BaSyxTCPServer;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11.  
  12. /**
  13.  * The control component provides an additional abstraction for native device handling and has a specified interface.
  14.  * It can also be connected to the virtual automation bus.
  15.  * For more information on control components, see:
  16.  * https://wiki.eclipse.org/BaSyx_/_Documentation_/_API_/_ControlComponent
  17.  * 
  18.  * There, the VAB API is specified:
  19.  * https://wiki.eclipse.org/BaSyx_/_Documentation_/_API_/_ControlComponent#Virtual_Automation_Bus_.28VAB.29_implementation
  20.  * 
  21.  * In this HandsOn, a given control component for the virtual (proprietary) oven is utilized via the VAB.
  22.  * 
  23.  * Expected console output in this HandsOn:
  24.  * - state outputs from the OvenControlComponent
  25.  * - oven is activated and deactivated multiple times (not manually, but automatically using the control component this
  26.  * time)
  27.  * - temperature values at ~30
  28.  * - the oven cooling down after the control component is finished
  29.  */
  30. public class Scenario3 {
  31. 	// Initializes a logger for the output
  32. 	private static final Logger logger = LoggerFactory.getLogger(Scenario3.class);
  33.  
  34. 	public static void main(String[] args) throws Exception {
  35. 		// Create the virtual oven specific to this HandsOn
  36. 		Oven myOven = new Oven();
  37.  
  38. 		// Write a function, that starts a control component for the virtual oven
  39. 		startMyControlComponent(myOven);
  40.  
  41. 		// Connect to the control component, see service interface here
  42. 		// This code also shows how to directly connect to a known location without
  43. 		// using the Registry/ConnectionManager.
  44. 		// However, this assumes that the address of the Control Component will never
  45. 		// change
  46. 		VABElementProxy proxy = new VABElementProxy("", new JSONConnector(new BaSyxConnector("localhost", 4002)));
  47.  
  48. 		// Select the operation mode for heating
  49. 		proxy.setValue("STATUS/OPMODE", OvenControlComponent.OPMODE_HEAT);
  50.  
  51. 		// Start the selected operation in the control component
  52. 		proxy.invokeOperation("OPERATIONS/START");
  53. 		logger.info("Using the control component to start the HEAT operation");
  54. 		for (int i = 0; i < 10; i++) {
  55. 			Thread.sleep(1000);
  56. 			logger.info("CurrentTemperature: " + myOven.getSensor().readTemperature());
  57. 			// Return true, if the control component has completed its operation
  58. 			String currentState = (String) proxy.getValue("STATUS/EXST");
  59. 			if (currentState.equals(ExecutionState.COMPLETE.getValue())) {
  60. 				// Reset the control component
  61. 				proxy.invokeOperation("OPERATIONS/RESET");
  62. 				break;
  63. 			}
  64. 		}
  65.  
  66. 		logger.info("Waiting for oven to cool down...");
  67. 		Thread.sleep(2500);
  68. 		logger.info("CurrentTemperature: " + myOven.getSensor().readTemperature());
  69. 	}
  70.  
  71. 	public static void startMyControlComponent(Oven oven) {
  72. 		// Given is a local control component that can directly control the virtual oven device
  73. 		ControlComponent cc = new OvenControlComponent(oven);
  74.  
  75. 		// Like the VAB model created before, the structure of the control component is a Map
  76. 		// Map ccModel = (Map) cc;
  77.  
  78. 		// Create a server for the Control Component and provide it in the VAB (at port 4002)
  79. 		VABMapProvider ccProvider = new VABMapProvider(cc);
  80. 		// This time, a BaSyx-specific TCP interface is used.
  81. 		// Likewise, it is also possible to wrap the control component using a http servlet as before
  82. 		BaSyxTCPServer<IModelProvider> server = new BaSyxTCPServer<>(ccProvider, 4002);
  83. 		server.start();
  84. 	}
  85. }

Oven Control Component

For this example, a simple control component exposing the HEAT opmode is created. The Control Component activates and deactivates the oven depending on the temperature multiple times.

Please note, that the OvenControlComponent takes some shortcuts for simplicity's sake in the context of this example. For example, having the control component also be its own ChangeListener may not be viable for a real world application.

  1. import org.eclipse.basyx.models.controlcomponent.ControlComponentChangeListener;
  2. import org.eclipse.basyx.models.controlcomponent.ExecutionMode;
  3. import org.eclipse.basyx.models.controlcomponent.ExecutionState;
  4. import org.eclipse.basyx.models.controlcomponent.OccupationState;
  5. import org.eclipse.basyx.models.controlcomponent.SimpleControlComponent;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8.  
  9. /**
  10.  * Control Component for controlling the oven. Has an additional operation mode named HEAT.
  11.  * This is a "black-box" example for a control component for the HandsOn.
  12.  */
  13. public class OvenControlComponent extends SimpleControlComponent implements ControlComponentChangeListener {
  14. 	private static final long serialVersionUID = 1L;
  15.         private static final Logger logger = LoggerFactory.getLogger(OvenControlComponent.class);
  16.  
  17. 	public static final String OPMODE_BASIC = "BSTATE";
  18. 	public static final String OPMODE_HEAT = "HEAT";
  19.  
  20. 	private Oven oven;
  21.  
  22. 	public OvenControlComponent(Oven oven) {
  23. 		this.oven = oven;
  24. 		addControlComponentChangeListener(this);
  25. 	}
  26.  
  27. 	@Override
  28. 	public void onChangedExecutionState(ExecutionState newExecutionState) {
  29. 		logger.info("OvenControlComponent: new execution state: " + newExecutionState);
  30. 		if (newExecutionState == ExecutionState.EXECUTE) {
  31. 			if (this.getOperationMode().equals(OPMODE_HEAT)) {
  32. 				controlHeater();
  33. 			} else {
  34. 				setExecutionState(ExecutionState.COMPLETE.getValue());
  35. 			}
  36. 		}
  37. 	}
  38.  
  39. 	protected void controlHeater() {
  40. 		new Thread(() -> {
  41. 			for (int i = 0; i < 50; i++) {
  42. 				if (oven.getSensor().readTemperature() < 30.0d) {
  43. 					oven.getHeater().activate();
  44. 				} else {
  45. 					oven.getHeater().deactivate();
  46. 				}
  47. 				try {
  48. 					Thread.sleep(100);
  49. 				} catch (InterruptedException e) {
  50. 					e.printStackTrace();
  51. 				}
  52. 			}
  53. 			oven.getHeater().deactivate();
  54. 			setExecutionState(ExecutionState.COMPLETE.getValue());
  55. 		}).start();
  56. 	}
  57.  
  58. 	@Override
  59. 	public void onVariableChange(String varName, Object newValue) {
  60. 	}
  61.  
  62. 	@Override
  63. 	public void onNewOccupier(String occupierId) {
  64. 	}
  65.  
  66. 	@Override
  67. 	public void onNewOccupationState(OccupationState state) {
  68. 	}
  69.  
  70. 	@Override
  71. 	public void onChangedExecutionMode(ExecutionMode newExecutionMode) {
  72. 	}
  73.  
  74. 	@Override
  75. 	public void onChangedOperationMode(String newOperationMode) {
  76. 	}
  77.  
  78. 	@Override
  79. 	public void onChangedWorkState(String newWorkState) {
  80. 	}
  81.  
  82. 	@Override
  83. 	public void onChangedErrorState(String newWorkState) {
  84. 	}
  85. }

Expected Output

The first output will be the info about the execution state of the OvenControlComponent, which will be EXECUTE. After this the heater will be deactivated and activated multiple times and log the current temperature at a few intervals. Once the execution state changes to COMPLETE the temperature will fall and the state will change to IDLE as the temperature falls again.

15:50:07.729 [org.eclipse.basyx.vab.protocol.basyx.server.VABBaSyxTCPInterface 1629726607727] INFO  i.OvenControlComponent - OvenControlComponent: new execution state: EXECUTE
Heater: activated
15:50:07.731 [main] INFO  i.Scenario3 - Using the control component to start the HEAT operation
Heater: deactivated
Heater: activated
...
15:50:08.735 [main] INFO  i.Scenario3 - CurrentTemperature: 31.27908533
...
15:50:09.744 [main] INFO  i.Scenario3 - CurrentTemperature: 30.035964578619193
...
15:50:13.160 [Thread-4] INFO  i.OvenControlComponent - OvenControlComponent: new execution state: COMPLETE
15:50:13.781 [main] INFO  i.Scenario3 - CurrentTemperature: 25.93672972478958
15:50:13.784 [org.eclipse.basyx.vab.protocol.basyx.server.VABBaSyxTCPInterface 1629726613784] INFO  i.OvenControlComponent - OvenControlComponent: new execution state: IDLE
15:50:13.785 [main] INFO  i.Scenario3 - Waiting for oven to cool down...
15:50:16.297 [main] INFO  i.Scenario3 - CurrentTemperature: 20.526168681839124

Back to the top