Add virtual sensors
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
<?import javafx.scene.layout.FlowPane?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.Spinner?>
|
||||
<?import javafx.scene.control.TableView?>
|
||||
<?import javafx.scene.control.TableColumn?>
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
|
||||
<center>
|
||||
<SplitPane>
|
||||
@@ -29,6 +31,12 @@
|
||||
<Button fx:id="visualizeBtn" onAction="#onVisualizeClick">Visualize</Button>
|
||||
</right>
|
||||
</BorderPane>
|
||||
<TableView fx:id="sourcesView">
|
||||
<columns>
|
||||
<TableColumn fx:id="sourceWeight" text="Weight" />
|
||||
<TableColumn fx:id="sourceId" text="Id" />
|
||||
</columns>
|
||||
</TableView>
|
||||
</VBox>
|
||||
</SplitPane>
|
||||
</center>
|
||||
|
@@ -3,18 +3,24 @@ 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.table.WeightSpinnerTableCell;
|
||||
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.model.sensor.VirtualSensor;
|
||||
import fr.uca.iut.clfreville2.persistence.StubSensorRegistryLoader;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.text.Text;
|
||||
@@ -42,6 +48,15 @@ public class MainWindows {
|
||||
@FXML
|
||||
private Button visualizeBtn;
|
||||
|
||||
@FXML
|
||||
private TableView<VirtualSensor.DataSource> sourcesView;
|
||||
|
||||
@FXML
|
||||
private TableColumn<VirtualSensor.DataSource, VirtualSensor.DataSource> sourceWeight;
|
||||
|
||||
@FXML
|
||||
private TableColumn<VirtualSensor.DataSource, String> sourceId;
|
||||
|
||||
@FXML
|
||||
private Spinner<Integer> updateInterval;
|
||||
|
||||
@@ -92,6 +107,7 @@ public class MainWindows {
|
||||
private void initialize() {
|
||||
bindSensorList();
|
||||
bindActiveButtons();
|
||||
bindSources();
|
||||
bindUpdate();
|
||||
}
|
||||
|
||||
@@ -102,10 +118,15 @@ public class MainWindows {
|
||||
sensorsList.getSelectionModel().selectedItemProperty().addListener((list, oldValue, newValue) -> {
|
||||
if (oldValue != null) {
|
||||
sensorName.textProperty().unbindBidirectional(oldValue.nameProperty());
|
||||
sourcesView.itemsProperty().unbind();
|
||||
sourcesView.setItems(FXCollections.emptyObservableList());
|
||||
}
|
||||
if (newValue != null) {
|
||||
sensorId.textProperty().bind(newValue.displayNameExpression());
|
||||
sensorName.textProperty().bindBidirectional(newValue.nameProperty());
|
||||
if (newValue instanceof VirtualSensor virtual) {
|
||||
sourcesView.itemsProperty().bind(virtual.sourcesProperty());
|
||||
}
|
||||
} else {
|
||||
sensorId.textProperty().unbind();
|
||||
sensorId.setText(null);
|
||||
@@ -122,6 +143,13 @@ public class MainWindows {
|
||||
visualizeBtn.visibleProperty().bind(sensorsList.getSelectionModel().selectedItemProperty().isNotNull());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void bindSources() {
|
||||
sourceWeight.setCellValueFactory(cell -> new SimpleObjectProperty<>(cell.getValue()));
|
||||
sourceWeight.setCellFactory(cell -> new WeightSpinnerTableCell());
|
||||
sourceId.setCellValueFactory(cell -> cell.getValue().sensor().idProperty().asString());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void bindUpdate() {
|
||||
updateInterval.getValueFactory().valueProperty().bindBidirectional(ticker.millisPerTickProperty().asObject());
|
||||
|
@@ -0,0 +1,28 @@
|
||||
package fr.uca.iut.clfreville2.gui.table;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.sensor.VirtualSensor;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.SpinnerValueFactory;
|
||||
import javafx.scene.control.TableCell;
|
||||
|
||||
public class WeightSpinnerTableCell extends TableCell<VirtualSensor.DataSource, VirtualSensor.DataSource> {
|
||||
|
||||
private final Spinner<Double> weight = new Spinner<>(new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0D, 10.0));
|
||||
private ObjectProperty<Double> weightValueObj;
|
||||
|
||||
@Override
|
||||
protected void updateItem(VirtualSensor.DataSource item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty) {
|
||||
if (weightValueObj != null) {
|
||||
weight.getValueFactory().valueProperty().unbindBidirectional(weightValueObj);
|
||||
}
|
||||
setGraphic(null);
|
||||
} else {
|
||||
weightValueObj = item.weightProperty().asObject();
|
||||
weight.getValueFactory().valueProperty().bindBidirectional(weightValueObj);
|
||||
setGraphic(weight);
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,6 +3,7 @@ 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.VirtualSensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
|
||||
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||
import javafx.beans.property.ListProperty;
|
||||
@@ -44,6 +45,16 @@ public class SensorRegistry implements Tickable, Iterable<Sensor> {
|
||||
return register(new AutoSensor(nextIdSupplier.getAsInt(), name, strategy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new virtual sensor and add it to the registry.
|
||||
*
|
||||
* @param name The name of the sensor.
|
||||
* @return The sensor created.
|
||||
*/
|
||||
public VirtualSensor createVirtual(String name) {
|
||||
return register(new VirtualSensor(nextIdSupplier.getAsInt(), name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new sensor to the registry.
|
||||
*
|
||||
|
73
src/fr/uca/iut/clfreville2/model/sensor/VirtualSensor.java
Normal file
73
src/fr/uca/iut/clfreville2/model/sensor/VirtualSensor.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package fr.uca.iut.clfreville2.model.sensor;
|
||||
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.ListProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.property.ReadOnlyListProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class VirtualSensor extends Sensor {
|
||||
|
||||
private final ObservableList<DataSource> sources = FXCollections.observableArrayList();
|
||||
private final ListProperty<DataSource> sourcesProperty = new SimpleListProperty<>(sources);
|
||||
private final SimpleDoubleProperty temperature = new SimpleDoubleProperty();
|
||||
private final ChangeListener<Number> changeHandler = (s, old, next) -> compute();
|
||||
|
||||
public VirtualSensor(int id, String name) {
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public void addSource(Sensor sensor, double weight) {
|
||||
sources.add(new DataSource(requireNonNull(sensor, "sensor"), weight));
|
||||
sensor.temperatureProperty().addListener(changeHandler);
|
||||
}
|
||||
|
||||
public boolean removeSource(Sensor sensor) {
|
||||
return sources.removeIf(source -> {
|
||||
if (source.sensor().equals(sensor)) {
|
||||
sensor.temperatureProperty().removeListener(changeHandler);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyDoubleProperty temperatureProperty() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public ReadOnlyListProperty<DataSource> sourcesProperty() {
|
||||
return sourcesProperty;
|
||||
}
|
||||
|
||||
protected void compute() {
|
||||
temperature.set(sources.stream()
|
||||
.mapToDouble(sensor -> sensor.temperature() * sensor.weight())
|
||||
.sum() /
|
||||
sources.stream()
|
||||
.mapToDouble(DataSource::weight)
|
||||
.sum());
|
||||
}
|
||||
|
||||
public record DataSource(Sensor sensor, DoubleProperty weightProperty) {
|
||||
|
||||
public DataSource(Sensor sensor, double weight) {
|
||||
this(sensor, new SimpleDoubleProperty(weight));
|
||||
}
|
||||
|
||||
public double temperature() {
|
||||
return sensor().getTemperature();
|
||||
}
|
||||
|
||||
public double weight() {
|
||||
return weightProperty.doubleValue();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,15 +1,19 @@
|
||||
package fr.uca.iut.clfreville2.persistence;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
||||
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.VirtualSensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.auto.RandomVariationStrategy;
|
||||
|
||||
public class StubSensorRegistryLoader implements SensorRegistryLoader {
|
||||
@Override
|
||||
public SensorRegistry load() {
|
||||
SensorRegistry registry = new SensorRegistry();
|
||||
registry.createManual("Sensor 1");
|
||||
registry.createManual("Sensor 2");
|
||||
registry.createAuto("Sensor 3", new RandomVariationStrategy(5));
|
||||
registry.createManual("Manual 1");
|
||||
registry.createManual("Manual 2");
|
||||
AutoSensor autoSensor = registry.createAuto("Random 1", new RandomVariationStrategy(5));
|
||||
VirtualSensor virtualSensor = registry.createVirtual("Virtual 1");
|
||||
virtualSensor.addSource(autoSensor, 1.0D);
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user