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 1"

m (Adds comment for whole class)
m (Update output)
 
(8 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
= Example 1 - Local VAB Access =
 
In this first example, an oven will be connected to the VAB. Next, the VAB will be used to access and control the oven.  
 
In this first example, an oven will be connected to the VAB. Next, the VAB will be used to access and control the oven.  
 
{|style="text-align: center; width: 100%"
 
{|style="text-align: center; width: 100%"
|[[File:BaSyx_Introductory_Examples_Java_1.png]]
+
|[[File:BaSyx_Introductory_Examples_Java_1.png|center|1024px]]
 
|}
 
|}
 +
== Example Code ==
 
To do this, we first need to describe the oven in a model and provide this model to the VAB. As [[BaSyx_/_Documentation_/_VAB_Providers | described]], maps can be used for easy definition of models. Thus, an initial model of the oven using Maps is defined. Additionally, the already existing interface to the oven has to be integrated into the map model. To do this, the [[ BaSyx_/_Documentation_/_Lambda_Provider | Lambda Provider]] is used.  
 
To do this, we first need to describe the oven in a model and provide this model to the VAB. As [[BaSyx_/_Documentation_/_VAB_Providers | described]], maps can be used for easy definition of models. Thus, an initial model of the oven using Maps is defined. Additionally, the already existing interface to the oven has to be integrated into the map model. To do this, the [[ BaSyx_/_Documentation_/_Lambda_Provider | Lambda Provider]] is used.  
  
<syntaxhighlight lang="java" style="margin-left: 4em">
+
<syntaxhighlight lang="java" style="margin-left: 4em" line>
 +
import java.util.HashMap;
 +
import java.util.Map;
 +
import java.util.function.Function;
 +
import java.util.function.Supplier;
 +
 
 +
import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
 +
import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProvider;
 +
import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProviderHelper;
 +
import org.slf4j.Logger;
 +
import org.slf4j.LoggerFactory;
 +
 
 
/**
 
/**
 
  * The Virtual Automation Bus maps communication semantics to five simple primitives:
 
  * The Virtual Automation Bus maps communication semantics to five simple primitives:
Line 30: Line 43:
 
  *  
 
  *  
 
  */
 
  */
public class Example1 {
+
public class Scenario1 {
 
// Initializes a logger for the output
 
// Initializes a logger for the output
private static final Logger logger = LoggerFactory.getLogger(Example1.class);
+
private static final Logger logger = LoggerFactory.getLogger(Scenario1.class);
  
 
public static void main(String[] args) throws Exception {
 
public static void main(String[] args) throws Exception {
// Create a model for an oven device. Models in the BaSyx Java SDK are based on HashMaps.
+
// Create a model for an oven device. Models in the BaSyx Java SDK are based on
 +
// HashMaps.
 
Map<String, Object> myOvenModel = createMyOvenModel(new Oven());
 
Map<String, Object> myOvenModel = createMyOvenModel(new Oven());
  
// Wrap the device model in a VAB model provider. In this case, a VABLambdaProvider is used that enables dynamic
+
// Wrap the device model in a VAB model provider. In this case, a
// resolution of model properties.
+
// VABLambdaProvider is used that enables dynamic resolution of model
// There are also other providers like the VABMapProvider and the FileSystemProvider
+
// properties. There are also other providers like the VABMapProvider and the
 +
// FileSystemProvider
 
IModelProvider provider = new VABLambdaProvider(myOvenModel);
 
IModelProvider provider = new VABLambdaProvider(myOvenModel);
  
// Now you can access the properties of the oven via the five primitives using the model provider.
+
// Now you can access the properties of the oven via the five primitives using
 +
// the model provider.
 
// CREATE: IModelProvider::createValue
 
// CREATE: IModelProvider::createValue
 
// DELETE: IModelProvider::deleteValue
 
// DELETE: IModelProvider::deleteValue
Line 49: Line 65:
 
// UPDATE: IModelProvider::setModelPropertyValue
 
// UPDATE: IModelProvider::setModelPropertyValue
 
// INVOKE: IModelProvider::invokeOperation
 
// INVOKE: IModelProvider::invokeOperation
String id = (String) provider.getModelPropertyValue("/properties/id");
+
 
 +
String id = (String) provider.getValue("/properties/id");
 
logger.info("Heater id: " + id);
 
logger.info("Heater id: " + id);
// NOTE A: getModelPropertyValue has "Object" as the return type, so you probably will have to cast the result
+
// NOTE A: getModelPropertyValue has "Object" as the return type, so you
// to the appropriate type.
+
// probably will have to cast the result to the appropriate type.
// NOTE B: The argument "/properties/id" references the static id property of the model. This path depends
+
// NOTE B: The argument "/properties/id" references the static id property of
// on the structure of the HashMap => /properties/id assumes that the model structure matches the intended map
+
// the model. This path depends on the structure of the HashMap =>
 +
// /properties/id assumes that the model structure matches the intended map
 
// structure that is proposed at the beginning of "helperfunction".
 
// structure that is proposed at the beginning of "helperfunction".
  
Line 60: Line 78:
 
provider.invokeOperation("/operations/activateOven");
 
provider.invokeOperation("/operations/activateOven");
  
// Now that the oven is on, we don't want it to get too hot, so we implement a simple bang-bang controller
+
// Now that the oven is on, we don't want it to get too hot, so we implement a
 +
// simple bang-bang controller
 
for (int i = 0; i < 100; i++) {
 
for (int i = 0; i < 100; i++) {
 
// Pause for 100ms
 
// Pause for 100ms
Line 66: Line 85:
  
 
// Retrieve the current temperature from the model provider
 
// Retrieve the current temperature from the model provider
double temperature = (double) provider.getModelPropertyValue("/properties/temperature");
+
double temperature = (double) provider.getValue("/properties/temperature");
 
logger.info("Current temperature: " + temperature);
 
logger.info("Current temperature: " + temperature);
  
Line 86: Line 105:
 
* ),
 
* ),
 
* operations: new HashMap(
 
* operations: new HashMap(
* deactivateOven: *Function* for deactivating the oven,
+
* activateOven: *Function* for activating the oven,
* activateOven: *Function* for activating the oven
+
* deactivateOven: *Function* for deactivating the oven
 
* )
 
* )
 
* )
 
* )
Line 94: Line 113:
 
// Create an empty container for custom properties
 
// Create an empty container for custom properties
 
Map<String, Object> properties = new HashMap<>();
 
Map<String, Object> properties = new HashMap<>();
 +
 
// Add a static element
 
// Add a static element
 
properties.put("id", "heater01");
 
properties.put("id", "heater01");
 +
 
// Now we want to create a dynamic property that can resolve its value during runtime
 
// Now we want to create a dynamic property that can resolve its value during runtime
 
// 1. Create a supplier function that can determine the oven temperature using the +sensor
 
// 1. Create a supplier function that can determine the oven temperature using the +sensor
 
Supplier<Object> lambdaFunction = () -> oven.getSensor().readTemperature();
 
Supplier<Object> lambdaFunction = () -> oven.getSensor().readTemperature();
 +
 
// 2. Use a VABLambdaProviderHelper in order to create a lambda property out of that supplier
 
// 2. Use a VABLambdaProviderHelper in order to create a lambda property out of that supplier
 
// NOTE: A setter function is not required (=> null), because a sensor temperature is "read only"
 
// NOTE: A setter function is not required (=> null), because a sensor temperature is "read only"
 
Map<String, Object> lambdaProperty = VABLambdaProviderHelper.createSimple(lambdaFunction, null);
 
Map<String, Object> lambdaProperty = VABLambdaProviderHelper.createSimple(lambdaFunction, null);
 +
 
// 3. Add that lambda property to the model exactly like the static property before
 
// 3. Add that lambda property to the model exactly like the static property before
 
properties.put("temperature", lambdaProperty);
 
properties.put("temperature", lambdaProperty);
Line 107: Line 130:
 
// Create an empty container for custom operations
 
// Create an empty container for custom operations
 
Map<String, Object> operations = new HashMap<>();
 
Map<String, Object> operations = new HashMap<>();
 +
 
// Add a function that activates the oven and implements a functional interface
 
// Add a function that activates the oven and implements a functional interface
 +
// Creation of this function needs to follow this method signature for Function.
 +
// In the release version 1.1, this will be simplified.
 
Function<Object, Object> activateFunction = (args) -> {
 
Function<Object, Object> activateFunction = (args) -> {
 
oven.getHeater().activate();
 
oven.getHeater().activate();
 
return null;
 
return null;
 
};
 
};
 +
 
// Add a function that deactivates the oven and implements a functional interface
 
// Add a function that deactivates the oven and implements a functional interface
 
operations.put("activateOven", activateFunction);
 
operations.put("activateOven", activateFunction);
Line 120: Line 147:
 
return null;
 
return null;
 
};
 
};
 +
 
// Add a function that deactivates the oven and implements a functional interface
 
// Add a function that deactivates the oven and implements a functional interface
 
operations.put("deactivateOven", deactivateFunction);
 
operations.put("deactivateOven", deactivateFunction);
Line 131: Line 159:
 
}
 
}
  
 +
</syntaxhighlight>
 +
 +
== Expected Output ==
 +
 +
You should see something like the following few lines in your console.
 +
The time at the start of each will be your current time.
 +
At first you will see what id the selected heater has.
 +
The temperature values at the end of the lines may differ by a small margin and will fluctuate between ~30 and ~40 as the heater is activated or deactivated multiple times.
 +
 +
<pre style="margin-left: 4em">
 +
15:07:57.283 [main] INFO  i.Scenario1 - Heater id: heater01
 +
Heater: activated
 +
15:07:57.394 [main] INFO  i.Scenario1 - Current temperature: 23.0
 +
15:07:57.502 [main] INFO  i.Scenario1 - Current temperature: 25.7
 +
15:07:57.610 [main] INFO  i.Scenario1 - Current temperature: 28.13
 +
15:07:57.719 [main] INFO  i.Scenario1 - Current temperature: 30.317
 +
15:07:57.828 [main] INFO  i.Scenario1 - Current temperature: 32.2853
 +
15:07:57.936 [main] INFO  i.Scenario1 - Current temperature: 34.05677
 +
15:07:58.045 [main] INFO  i.Scenario1 - Current temperature: 35.651093
 +
15:07:58.155 [main] INFO  i.Scenario1 - Current temperature: 37.08598370000001
 +
15:07:58.265 [main] INFO  i.Scenario1 - Current temperature: 38.37738533000001
 +
15:07:58.373 [main] INFO  i.Scenario1 - Current temperature: 39.53964679700001
 +
15:07:58.482 [main] INFO  i.Scenario1 - Current temperature: 40.58568211730001
 +
Heater: deactivated
 +
15:07:58.591 [main] INFO  i.Scenario1 - Current temperature: 38.52711390557001
 +
15:07:58.700 [main] INFO  i.Scenario1 - Current temperature: 36.674402515013014
 +
15:07:58.809 [main] INFO  i.Scenario1 - Current temperature: 35.00696226351172
 +
15:07:58.918 [main] INFO  i.Scenario1 - Current temperature: 33.50626603716054
 +
15:07:59.025 [main] INFO  i.Scenario1 - Current temperature: 32.15563943344449
 +
15:07:59.133 [main] INFO  i.Scenario1 - Current temperature: 30.940075490100043
 +
15:07:59.242 [main] INFO  i.Scenario1 - Current temperature: 29.846067941090038
 +
...
 +
</pre>
 +
 +
= Oven Stub =
 +
Any implementation supporting the used interfaces of the oven can be used. In the following, an example implementation is given:
 +
 +
== Oven Code ==
 +
<syntaxhighlight lang="java" style="margin-left: 4em" line>
 +
/**
 +
* Oven containing a heater and a temperature sensor
 +
*/
 +
public class Oven {
 +
private Heater heater;
 +
private TemperatureSensor sensor;
 +
 +
 +
public Oven() {
 +
heater = new Heater();
 +
sensor = new TemperatureSensor(heater);
 +
}
 +
 +
public Heater getHeater() {
 +
return heater;
 +
}
 +
 +
public TemperatureSensor getSensor() {
 +
return sensor;
 +
}
 +
}
 +
</syntaxhighlight>
 +
 +
== Heater Code ==
 +
<syntaxhighlight lang="java" style="margin-left: 4em">
 +
/**
 +
* Simple heater with two states: activated or deactivated
 +
*
 +
*/
 +
public class Heater {
 +
private boolean isActive = false;
 +
 +
public void activate() {
 +
if (!isActive) {
 +
System.out.println("Heater: activated");
 +
isActive = true;
 +
}
 +
}
 +
 +
public void deactivate() {
 +
if (isActive) {
 +
System.out.println("Heater: deactivated");
 +
isActive = false;
 +
}
 +
}
 +
 +
public boolean isActive() {
 +
return isActive;
 +
}
 +
}
 +
</syntaxhighlight>
 +
 +
== TemperatureSensor Code ==
 +
<syntaxhighlight lang="java" style="margin-left: 4em" line>
 +
/**
 +
* A sensor for reading a temperature value that is dependent on a heater
 +
*/
 +
public class TemperatureSensor {
 +
private final double maxTemperature = 50;
 +
private final double minTemperature = 20;
 +
private final double changeRate = 0.1d;
 +
 +
private double currentTemperature = 20.0;
 +
 +
public TemperatureSensor(final Heater heater) {
 +
// Start a new Thread that updates the temperature in every tick
 +
new Thread(() -> {
 +
while (true) {
 +
try {
 +
Thread.sleep(100);
 +
} catch (InterruptedException e) {
 +
e.printStackTrace();
 +
}
 +
double targetTemperature = minTemperature;
 +
if (heater.isActive()) {
 +
targetTemperature = maxTemperature;
 +
}
 +
currentTemperature = (1 - changeRate) * currentTemperature + changeRate * targetTemperature;
 +
}
 +
}).start();
 +
}
 +
 +
public double readTemperature() {
 +
return currentTemperature;
 +
}
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>

Latest revision as of 09:34, 23 August 2021

Example 1 - Local VAB Access

In this first example, an oven will be connected to the VAB. Next, the VAB will be used to access and control the oven.

BaSyx Introductory Examples Java 1.png

Example Code

To do this, we first need to describe the oven in a model and provide this model to the VAB. As described, maps can be used for easy definition of models. Thus, an initial model of the oven using Maps is defined. Additionally, the already existing interface to the oven has to be integrated into the map model. To do this, the Lambda Provider is used.

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. import java.util.function.Function;
  4. import java.util.function.Supplier;
  5.  
  6. import org.eclipse.basyx.vab.modelprovider.api.IModelProvider;
  7. import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProvider;
  8. import org.eclipse.basyx.vab.modelprovider.lambda.VABLambdaProviderHelper;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11.  
  12. /**
  13.  * The Virtual Automation Bus maps communication semantics to five simple primitives:
  14.  * - CREATE, DELETE, RETRIEVE, UPDATE, INVOKE
  15.  * These primitive functions are represented in the IModelProvider interface.
  16.  * 
  17.  * In this HandsOn, a local model provider is created that gives access to an oven model via these primitives.
  18.  * Remote connections and the AAS metamodel is excluded for now.
  19.  * 
  20.  * A virtual "Oven" with a heater and a temperature sensor is used.
  21.  * It is specific to this HandsOn and can be used in the following way:
  22.  * Oven oven = new Oven()
  23.  * Heater heater = oven.getHeater();
  24.  * heater.activate(); // turns the heater on
  25.  * heater.deactivate(); // turns the heater off
  26.  * TemperatureSensor sensor = oven.getSensor();
  27.  * double temperature = sensor.readTemperature(); // gets the current temperature in the oven
  28.  * 
  29.  * 
  30.  * Expected console output in this HandsOn:
  31.  * - the heater id
  32.  * - oven is activated and deactivated multiple times
  33.  * - temperature values between 30 and 40
  34.  * 
  35.  */
  36. public class Scenario1 {
  37. 	// Initializes a logger for the output
  38. 	private static final Logger logger = LoggerFactory.getLogger(Scenario1.class);
  39.  
  40. 	public static void main(String[] args) throws Exception {
  41. 		// Create a model for an oven device. Models in the BaSyx Java SDK are based on
  42. 		// HashMaps.
  43. 		Map<String, Object> myOvenModel = createMyOvenModel(new Oven());
  44.  
  45. 		// Wrap the device model in a VAB model provider. In this case, a
  46. 		// VABLambdaProvider is used that enables dynamic resolution of model
  47. 		// properties. There are also other providers like the VABMapProvider and the
  48. 		// FileSystemProvider
  49. 		IModelProvider provider = new VABLambdaProvider(myOvenModel);
  50.  
  51. 		// Now you can access the properties of the oven via the five primitives using
  52. 		// the model provider.
  53. 		// CREATE: IModelProvider::createValue
  54. 		// DELETE: IModelProvider::deleteValue
  55. 		// RETRIEVE: IModelProvider::getModelPropertyValue
  56. 		// UPDATE: IModelProvider::setModelPropertyValue
  57. 		// INVOKE: IModelProvider::invokeOperation
  58.  
  59. 		String id = (String) provider.getValue("/properties/id");
  60. 		logger.info("Heater id: " + id);
  61. 		// NOTE A: getModelPropertyValue has "Object" as the return type, so you
  62. 		// probably will have to cast the result to the appropriate type.
  63. 		// NOTE B: The argument "/properties/id" references the static id property of
  64. 		// the model. This path depends on the structure of the HashMap =>
  65. 		// /properties/id assumes that the model structure matches the intended map
  66. 		// structure that is proposed at the beginning of "helperfunction".
  67.  
  68. 		// The operations can be invoked via the model provider like this:
  69. 		provider.invokeOperation("/operations/activateOven");
  70.  
  71. 		// Now that the oven is on, we don't want it to get too hot, so we implement a
  72. 		// simple bang-bang controller
  73. 		for (int i = 0; i < 100; i++) {
  74. 			// Pause for 100ms
  75. 			Thread.sleep(100);
  76.  
  77. 			// Retrieve the current temperature from the model provider
  78. 			double temperature = (double) provider.getValue("/properties/temperature");
  79. 			logger.info("Current temperature: " + temperature);
  80.  
  81. 			// Turn the oven on/off, depending on the defined temperature range
  82. 			if (temperature > 40) {
  83. 				provider.invokeOperation("/operations/deactivateOven");
  84. 			} else if (temperature < 30) {
  85. 				provider.invokeOperation("/operations/activateOven");
  86. 			}
  87. 		}
  88. 	}
  89.  
  90. 	public static Map<String, Object> createMyOvenModel(Oven oven) {
  91. 		/*  Pseudo-Code for the intended map structure of the oven model:
  92. 		 * 	myModel = new HashMap(
  93. 		 * 		properties: new HashMap(
  94. 	 	 * 			id: "heater01", 
  95. 	 	 * 			temperature: Dynamic *Lambda-Property* that represents the current oven temperature,
  96. 		 * 		),
  97. 		 * 		operations: new HashMap(
  98. 		 * 			activateOven: *Function* for activating the oven,
  99. 	 	 * 			deactivateOven: *Function* for deactivating the oven
  100. 	 	 * 		)
  101. 	 	 * 	)
  102. 		 */
  103.  
  104. 		// Create an empty container for custom properties
  105. 		Map<String, Object> properties = new HashMap<>();
  106.  
  107. 		// Add a static element
  108. 		properties.put("id", "heater01");
  109.  
  110. 		// Now we want to create a dynamic property that can resolve its value during runtime
  111. 		// 1. Create a supplier function that can determine the oven temperature using the +sensor
  112. 		Supplier<Object> lambdaFunction = () -> oven.getSensor().readTemperature();
  113.  
  114. 		// 2. Use a VABLambdaProviderHelper in order to create a lambda property out of that supplier
  115. 		// NOTE: A setter function is not required (=> null), because a sensor temperature is "read only"
  116. 		Map<String, Object> lambdaProperty = VABLambdaProviderHelper.createSimple(lambdaFunction, null);
  117.  
  118. 		// 3. Add that lambda property to the model exactly like the static property before
  119. 		properties.put("temperature", lambdaProperty);
  120.  
  121. 		// Create an empty container for custom operations
  122. 		Map<String, Object> operations = new HashMap<>();
  123.  
  124. 		// Add a function that activates the oven and implements a functional interface
  125. 		// Creation of this function needs to follow this method signature for Function. 
  126. 		// In the release version 1.1, this will be simplified.
  127. 		Function<Object, Object> activateFunction = (args) -> {
  128. 			oven.getHeater().activate();
  129. 			return null;
  130. 		};
  131.  
  132. 		// Add a function that deactivates the oven and implements a functional interface
  133. 		operations.put("activateOven", activateFunction);
  134.  
  135. 		// Add a function that deactivates the oven and implements a functional interface
  136. 		Function<Object, Object> deactivateFunction = (args) -> {
  137. 			oven.getHeater().deactivate();
  138. 			return null;
  139. 		};
  140.  
  141. 		// Add a function that deactivates the oven and implements a functional interface
  142. 		operations.put("deactivateOven", deactivateFunction);
  143.  
  144. 		// Create a root map and return a single model with the created operations and properties
  145. 		Map<String, Object> myModel = new HashMap<>();
  146. 		myModel.put("operations", operations);
  147. 		myModel.put("properties", properties);
  148. 		return myModel;
  149. 	}
  150. }

Expected Output

You should see something like the following few lines in your console. The time at the start of each will be your current time. At first you will see what id the selected heater has. The temperature values at the end of the lines may differ by a small margin and will fluctuate between ~30 and ~40 as the heater is activated or deactivated multiple times.

15:07:57.283 [main] INFO  i.Scenario1 - Heater id: heater01
Heater: activated
15:07:57.394 [main] INFO  i.Scenario1 - Current temperature: 23.0
15:07:57.502 [main] INFO  i.Scenario1 - Current temperature: 25.7
15:07:57.610 [main] INFO  i.Scenario1 - Current temperature: 28.13
15:07:57.719 [main] INFO  i.Scenario1 - Current temperature: 30.317
15:07:57.828 [main] INFO  i.Scenario1 - Current temperature: 32.2853
15:07:57.936 [main] INFO  i.Scenario1 - Current temperature: 34.05677
15:07:58.045 [main] INFO  i.Scenario1 - Current temperature: 35.651093
15:07:58.155 [main] INFO  i.Scenario1 - Current temperature: 37.08598370000001
15:07:58.265 [main] INFO  i.Scenario1 - Current temperature: 38.37738533000001
15:07:58.373 [main] INFO  i.Scenario1 - Current temperature: 39.53964679700001
15:07:58.482 [main] INFO  i.Scenario1 - Current temperature: 40.58568211730001
Heater: deactivated
15:07:58.591 [main] INFO  i.Scenario1 - Current temperature: 38.52711390557001
15:07:58.700 [main] INFO  i.Scenario1 - Current temperature: 36.674402515013014
15:07:58.809 [main] INFO  i.Scenario1 - Current temperature: 35.00696226351172
15:07:58.918 [main] INFO  i.Scenario1 - Current temperature: 33.50626603716054
15:07:59.025 [main] INFO  i.Scenario1 - Current temperature: 32.15563943344449
15:07:59.133 [main] INFO  i.Scenario1 - Current temperature: 30.940075490100043
15:07:59.242 [main] INFO  i.Scenario1 - Current temperature: 29.846067941090038
...

Oven Stub

Any implementation supporting the used interfaces of the oven can be used. In the following, an example implementation is given:

Oven Code

  1. /**
  2.  * Oven containing a heater and a temperature sensor
  3.  */
  4. public class Oven {
  5. 	private Heater heater;
  6. 	private TemperatureSensor sensor;
  7.  
  8.  
  9. 	public Oven() {
  10. 		heater = new Heater();
  11. 		sensor = new TemperatureSensor(heater);
  12. 	}
  13.  
  14. 	public Heater getHeater() {
  15. 		return heater;
  16. 	}
  17.  
  18. 	public TemperatureSensor getSensor() {
  19. 		return sensor;
  20. 	}
  21. }

Heater Code

/**
 * Simple heater with two states: activated or deactivated
 *
 */
public class Heater {
	private boolean isActive = false;
 
	public void activate() {
		if (!isActive) {
			System.out.println("Heater: activated");
			isActive = true;
		}
	}
 
	public void deactivate() {
		if (isActive) {
			System.out.println("Heater: deactivated");
			isActive = false;
		}
	}
 
	public boolean isActive() {
		return isActive;
	}
}

TemperatureSensor Code

  1. /**
  2.  * A sensor for reading a temperature value that is dependent on a heater
  3.  */
  4. public class TemperatureSensor {
  5. 	private final double maxTemperature = 50;
  6. 	private final double minTemperature = 20;
  7. 	private final double changeRate = 0.1d;
  8.  
  9. 	private double currentTemperature = 20.0;
  10.  
  11. 	public TemperatureSensor(final Heater heater) {
  12. 		// Start a new Thread that updates the temperature in every tick
  13. 		new Thread(() -> {
  14. 			while (true) {
  15. 				try {
  16. 					Thread.sleep(100);
  17. 				} catch (InterruptedException e) {
  18. 					e.printStackTrace();
  19. 				}
  20. 				double targetTemperature = minTemperature;
  21. 				if (heater.isActive()) {
  22. 					targetTemperature = maxTemperature;
  23. 				}
  24. 				currentTemperature = (1 - changeRate) * currentTemperature + changeRate * targetTemperature;
  25. 			}
  26. 		}).start();
  27. 	}
  28.  
  29. 	public double readTemperature() {
  30. 		return currentTemperature;
  31. 	}
  32. }

Back to the top