Add virtual sensors

This commit is contained in:
2023-01-10 15:48:31 +01:00
parent ed17ebce49
commit 1972d81aa1
6 changed files with 155 additions and 3 deletions

View File

@@ -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>

View File

@@ -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());

View File

@@ -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);
}
}
}

View File

@@ -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.
*

View 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();
}
}
}

View File

@@ -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;
}
}