Add random temperature updates

main
Clément FRÉVILLE 3 years ago
parent cf47f08d5e
commit 448006bc34

@ -8,8 +8,7 @@
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.Button?>
<SplitPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0"
fx:controller="fr.uca.iut.clfreville2.gui.MainWindows">
<SplitPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
<ListView fx:id="sensorsList" />
<VBox alignment="TOP_CENTER">
<padding>

@ -1,7 +1,8 @@
package fr.uca.iut.clfreville2;
import fr.uca.iut.clfreville2.gui.FXMLUtils;
import fr.uca.iut.clfreville2.gui.MainWindows;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
@ -10,7 +11,7 @@ public class MainApplication extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(MainApplication.class.getResource("/windows/MainWindows.fxml"));
Parent root = FXMLUtils.load(MainApplication.class.getResource("/windows/MainWindows.fxml"), new MainWindows(primaryStage));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();

@ -0,0 +1,18 @@
package fr.uca.iut.clfreville2.gui;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import java.io.IOException;
import java.net.URL;
public final class FXMLUtils {
private FXMLUtils() {}
public static Parent load(URL location, Object controller) throws IOException {
FXMLLoader loader = new FXMLLoader(location);
loader.setController(controller);
return loader.load();
}
}

@ -3,25 +3,27 @@ package fr.uca.iut.clfreville2.gui;
import fr.uca.iut.clfreville2.gui.image.ImageSupplier;
import fr.uca.iut.clfreville2.gui.image.StandardImageSupplier;
import fr.uca.iut.clfreville2.gui.list.NameableListCell;
import fr.uca.iut.clfreville2.gui.thread.Ticker;
import fr.uca.iut.clfreville2.model.SensorRegistry;
import fr.uca.iut.clfreville2.model.binding.ToBooleanBinding;
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
import fr.uca.iut.clfreville2.persistence.StubSensorRegistryLoader;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MainWindows {
private final SensorRegistry registry = new StubSensorRegistryLoader().load();
private final ImageSupplier imageSupplier = new StandardImageSupplier();
private ModalFactory modalFactory;
private final Ticker ticker;
private final ModalFactory modalFactory;
@FXML
private ListView<Sensor> sensorsList;
@ -38,13 +40,20 @@ public class MainWindows {
@FXML
private Button visualizeBtn;
public MainWindows(Stage primaryStage) {
this.ticker = new Ticker(registry);
this.modalFactory = new ModalFactory(primaryStage);
primaryStage.setOnHidden((e) -> ticker.interrupt());
ticker.start();
}
@FXML
public void onChangeClick() {
Sensor selected = getSelectedSensor();
if (!(selected instanceof ManualSensor sensor)) {
return;
}
getModalFactory().createModal(selected, root -> {
modalFactory.createModal(selected, root -> {
Slider slider = new Slider(-5, 30, sensor.getTemperature());
slider.setBlockIncrement(0.5);
slider.setMajorTickUnit(0.5);
@ -61,7 +70,7 @@ public class MainWindows {
if (selected == null) {
return;
}
getModalFactory().createModal(selected, root -> {
modalFactory.createModal(selected, root -> {
ImageView imageView = new ImageView();
imageView.setPreserveRatio(true);
imageView.setFitHeight(200);
@ -107,15 +116,4 @@ public class MainWindows {
private Sensor getSelectedSensor() {
return sensorsList.getSelectionModel().getSelectedItem();
}
private ModalFactory getModalFactory() {
if (modalFactory == null) {
Scene scene = sensorsList.getScene();
if (scene == null) {
throw new IllegalStateException("No scene found");
}
modalFactory = new ModalFactory(scene.getWindow());
}
return modalFactory;
}
}

@ -0,0 +1,40 @@
package fr.uca.iut.clfreville2.gui.thread;
import fr.uca.iut.clfreville2.model.shared.Tickable;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
public class Ticker extends Thread {
private final Tickable tickable;
private final IntegerProperty millisPerTick = new SimpleIntegerProperty(250);
public Ticker(Tickable tickable) {
this.tickable = tickable;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(millisPerTick.getValue());
Platform.runLater(tickable::tick);
} catch (InterruptedException e) {
break;
}
}
}
public int getMillisPerTick() {
return millisPerTick.get();
}
public void setMillisPerTick(int millisPerTick) {
this.millisPerTick.set(millisPerTick);
}
public IntegerProperty millisPerTickProperty() {
return millisPerTick;
}
}

@ -1,7 +1,10 @@
package fr.uca.iut.clfreville2.model;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
import fr.uca.iut.clfreville2.model.sensor.Sensor;
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
import fr.uca.iut.clfreville2.model.shared.Tickable;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.SimpleListProperty;
@ -14,7 +17,7 @@ import java.util.function.IntSupplier;
/**
* A registry class to hold thermal sensors instances.
*/
public class SensorRegistry implements Iterable<Sensor> {
public class SensorRegistry implements Tickable, Iterable<Sensor> {
private final IntSupplier nextIdSupplier = new SequenceIntSupplier();
private final ObservableList<Sensor> sensors = FXCollections.observableArrayList();
@ -30,6 +33,17 @@ public class SensorRegistry implements Iterable<Sensor> {
return register(new ManualSensor(nextIdSupplier.getAsInt(), name));
}
/**
* Create a new auto sensor and add it to the registry.
*
* @param name The name of the sensor.
* @param strategy The strategy to update the sensor.
* @return The sensor created.
*/
public AutoSensor createAuto(String name, AutoUpdateStrategy strategy) {
return register(new AutoSensor(nextIdSupplier.getAsInt(), name, strategy));
}
/**
* Add a new sensor to the registry.
*
@ -60,6 +74,15 @@ public class SensorRegistry implements Iterable<Sensor> {
return sensorsList;
}
@Override
public void tick() {
for (Sensor sensor : sensors) {
if (sensor instanceof Tickable tickable) {
tickable.tick();
}
}
}
@Override
public Iterator<Sensor> iterator() {
return getSensors().iterator();

@ -0,0 +1,41 @@
package fr.uca.iut.clfreville2.model.sensor;
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
import fr.uca.iut.clfreville2.model.shared.Tickable;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import static java.util.Objects.requireNonNull;
/**
* A sensor that automatically create new temperatures.
*/
public class AutoSensor extends Sensor implements Tickable {
private final DoubleProperty temperature = new SimpleDoubleProperty();
private AutoUpdateStrategy updateStrategy;
public AutoSensor(int id, String name, AutoUpdateStrategy updateStrategy) {
super(id, name);
this.updateStrategy = requireNonNull(updateStrategy, "update strategy");
}
@Override
public void tick() {
temperature.set(updateStrategy.nextValue(this));
}
@Override
public ReadOnlyDoubleProperty temperatureProperty() {
return temperature;
}
public AutoUpdateStrategy getUpdateStrategy() {
return updateStrategy;
}
public void setUpdateStrategy(AutoUpdateStrategy updateStrategy) {
this.updateStrategy = requireNonNull(updateStrategy, "update strategy");
}
}

@ -2,16 +2,13 @@ package fr.uca.iut.clfreville2.model.sensor;
import fr.uca.iut.clfreville2.model.shared.TemperatureHolder;
import fr.uca.iut.clfreville2.model.shared.ObservableIdentifiable;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.binding.DoubleExpression;
import javafx.beans.binding.StringExpression;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableDoubleValue;
import static java.util.Objects.requireNonNull;

@ -0,0 +1,15 @@
package fr.uca.iut.clfreville2.model.sensor.auto;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
@FunctionalInterface
public interface AutoUpdateStrategy {
/**
* Computes the next value of the sensor.
*
* @param currentState The current state of the sensor.
* @return The next value of the sensor.
*/
double nextValue(AutoSensor currentState);
}

@ -0,0 +1,25 @@
package fr.uca.iut.clfreville2.model.sensor.auto;
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
import java.util.Random;
public class RandomVariationStrategy implements AutoUpdateStrategy {
private final Random random;
private final int maxVariation;
public RandomVariationStrategy(int maxVariation) {
this(new Random(), maxVariation);
}
public RandomVariationStrategy(Random random, int maxVariation) {
this.random = random;
this.maxVariation = maxVariation;
}
@Override
public double nextValue(AutoSensor currentState) {
return currentState.getTemperature() + random.nextInt(maxVariation * 2) - maxVariation;
}
}

@ -31,5 +31,12 @@ public interface ObservableIdentifiable extends Identifiable {
* @return The display name.
* @see #getDisplayName()
*/
StringExpression displayNameExpression();
default StringExpression displayNameExpression() {
return nameProperty();
}
@Override
default String getDisplayName() {
return displayNameExpression().get();
}
}

@ -0,0 +1,10 @@
package fr.uca.iut.clfreville2.model.shared;
@FunctionalInterface
public interface Tickable {
/**
* Tick the current object.
*/
void tick();
}

@ -1,6 +1,7 @@
package fr.uca.iut.clfreville2.persistence;
import fr.uca.iut.clfreville2.model.SensorRegistry;
import fr.uca.iut.clfreville2.model.sensor.auto.RandomVariationStrategy;
public class StubSensorRegistryLoader implements SensorRegistryLoader {
@Override
@ -8,7 +9,7 @@ public class StubSensorRegistryLoader implements SensorRegistryLoader {
SensorRegistry registry = new SensorRegistry();
registry.createManual("Sensor 1");
registry.createManual("Sensor 2");
registry.createManual("Sensor 3");
registry.createAuto("Sensor 3", new RandomVariationStrategy(5));
return registry;
}
}

Loading…
Cancel
Save