Merge pull request 'feature/views' (#1) from feature/views into pre_int
Reviewed-on: #1
This commit is contained in:
commit
de38f446fe
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Virtueller Gesundheitsassistent
|
||||||
|
Überblick
|
||||||
|
Dieses Projekt implementiert einen virtuellen Gesundheits- und Fahrassistenten
|
||||||
|
auf Basis von JavaFX. Die Anwendung visualisiert den aktuellen Zustand des
|
||||||
|
Fahrers (z.B. Müdigkeit, Ablenkung, Stress) und integriert:
|
||||||
|
- ein ML-Modell, das Zustände klassifiziert
|
||||||
|
- eine JavaFX-GUI mit mehreren Designvarianten
|
||||||
|
- OpenCV für Kamera-Preview
|
||||||
|
- Unreal Engine Pixel Streaming für einen sprechenden Avatar
|
||||||
|
- WebSocket-Kommunikation zur Steuerung des Avatars
|
||||||
|
|
||||||
|
Features
|
||||||
|
Architektur
|
||||||
|
Services
|
||||||
|
Views & UI-Struktur
|
||||||
|
Java-Version & Build
|
||||||
|
MQTT & Datenfluss
|
||||||
|
OpenCV
|
||||||
5
pom.xml
5
pom.xml
@ -43,6 +43,11 @@
|
|||||||
<version>4.12.0</version>
|
<version>4.12.0</version>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.51.1.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
package efi.projekt.virtueller_gesundheitsassistent;
|
package efi.projekt.virtueller_gesundheitsassistent;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.model.AppState;
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.service.DataPersistenceService;
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.service.EvaluationService;
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.service.MqttClientService;
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.service.StatisticsService;
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.service.UnrealWebSocketService;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import static javafx.application.Application.launch;
|
import static javafx.application.Application.launch;
|
||||||
@ -15,15 +21,50 @@ import javafx.stage.Stage;
|
|||||||
*/
|
*/
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
|
|
||||||
|
private final AppState appState = new AppState();
|
||||||
|
|
||||||
|
// Services
|
||||||
|
private DataPersistenceService persistenceService;
|
||||||
|
private StatisticsService statisticsService;
|
||||||
|
private EvaluationService evaluationService;
|
||||||
|
private UnrealWebSocketService unrealService;
|
||||||
|
private MqttClientService mqttService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws IOException {
|
public void start(Stage primaryStage) throws IOException {
|
||||||
// Lade FXML
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/efi/projekt/virtueller_gesundheitsassistent/view/FxView.fxml"));
|
|
||||||
Parent root = loader.load();
|
|
||||||
|
|
||||||
// Erzeuge Model & ViewModel
|
// =========================
|
||||||
|
// Services initialisieren
|
||||||
|
// =========================
|
||||||
|
|
||||||
|
// Unreal-WebService
|
||||||
|
unrealService = new UnrealWebSocketService("127.0.0.1");
|
||||||
|
|
||||||
Scene scene = new Scene(root, 1280, 720);
|
// MQTT-Service
|
||||||
|
mqttService = new MqttClientService();
|
||||||
|
|
||||||
|
// Datenbank initialisieren
|
||||||
|
persistenceService = new DataPersistenceService();
|
||||||
|
|
||||||
|
// Statistik-Service
|
||||||
|
statisticsService = new StatisticsService();
|
||||||
|
|
||||||
|
// Evaluationsservice
|
||||||
|
evaluationService = new EvaluationService(statisticsService, appState, unrealService);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// UI laden
|
||||||
|
// =========================
|
||||||
|
|
||||||
|
FXMLLoader loader = new FXMLLoader(
|
||||||
|
getClass().getResource(
|
||||||
|
"/efi/projekt/virtueller_gesundheitsassistent/view/MainView.fxml"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Scene scene = new Scene(loader.load(), 1400, 900);
|
||||||
|
|
||||||
primaryStage.setTitle("Virtueller Gesundheitsassistent");
|
primaryStage.setTitle("Virtueller Gesundheitsassistent");
|
||||||
primaryStage.setScene(scene);
|
primaryStage.setScene(scene);
|
||||||
@ -38,7 +79,6 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch();
|
launch(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.model;
|
||||||
|
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class AppState {
|
||||||
|
|
||||||
|
private final ObjectProperty<ProblemLevel> problemLevel =
|
||||||
|
new SimpleObjectProperty<>(ProblemLevel.NONE);
|
||||||
|
|
||||||
|
public ObjectProperty<ProblemLevel> problemLevelProperty() {
|
||||||
|
return problemLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProblemLevel getProblemLevel() {
|
||||||
|
return problemLevel.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProblemLevel(ProblemLevel level) {
|
||||||
|
problemLevel.set(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package efi.projekt.virtueller_gesundheitsassistent.model;
|
|
||||||
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author naumueller
|
|
||||||
*/
|
|
||||||
public class AssistantState {
|
|
||||||
|
|
||||||
private final ObjectProperty<ClassificationType> classification =
|
|
||||||
new SimpleObjectProperty<>(ClassificationType.NORMAL);
|
|
||||||
|
|
||||||
private final BooleanProperty speaking =
|
|
||||||
new SimpleBooleanProperty(false);
|
|
||||||
|
|
||||||
private final BooleanProperty monitoring =
|
|
||||||
new SimpleBooleanProperty(true);
|
|
||||||
|
|
||||||
public ObjectProperty<ClassificationType> classificationProperty() {
|
|
||||||
return classification;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanProperty speakingProperty() {
|
|
||||||
return speaking;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanProperty monitoringProperty() {
|
|
||||||
return monitoring;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
package efi.projekt.virtueller_gesundheitsassistent.model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author naumueller
|
|
||||||
*/
|
|
||||||
public enum ClassificationType {
|
|
||||||
NORMAL,
|
|
||||||
MUEDIGKEIT,
|
|
||||||
ABLENKUNG,
|
|
||||||
STRESS,
|
|
||||||
REAKTION
|
|
||||||
}
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public enum ProblemLevel {
|
||||||
|
NONE,
|
||||||
|
WARNING,
|
||||||
|
HIGH,
|
||||||
|
DISASTER
|
||||||
|
}
|
||||||
@ -1,37 +0,0 @@
|
|||||||
package efi.projekt.virtueller_gesundheitsassistent.service;
|
|
||||||
|
|
||||||
import efi.projekt.virtueller_gesundheitsassistent.model.ClassificationType;
|
|
||||||
import efi.projekt.virtueller_gesundheitsassistent.util.Logger;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author naumueller
|
|
||||||
*/
|
|
||||||
public class ClassificationService {
|
|
||||||
|
|
||||||
private static final String TOPIC = "Text";
|
|
||||||
|
|
||||||
public ClassificationService(MqttClientService mqtt) {
|
|
||||||
|
|
||||||
mqtt.subscribe(TOPIC, payload -> {
|
|
||||||
|
|
||||||
ClassificationType type = switch (payload) {
|
|
||||||
case "0" -> ClassificationType.NORMAL;
|
|
||||||
case "1" -> ClassificationType.MUEDIGKEIT;
|
|
||||||
case "2" -> ClassificationType.ABLENKUNG;
|
|
||||||
case "3" -> ClassificationType.REAKTION;
|
|
||||||
case "4" -> ClassificationType.STRESS;
|
|
||||||
default -> ClassificationType.NORMAL;
|
|
||||||
};
|
|
||||||
|
|
||||||
Logger.info("STATE", "Neue Klassifizierung: " + type);
|
|
||||||
|
|
||||||
Platform.runLater(() ->
|
|
||||||
StateService.getState()
|
|
||||||
.classificationProperty()
|
|
||||||
.set(type)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||||
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||||
|
*/
|
||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.util.Logger;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class DataPersistenceService {
|
||||||
|
|
||||||
|
private static final String DB_URL = "jdbc:sqlite:data/health.db";
|
||||||
|
|
||||||
|
public DataPersistenceService() {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
try (
|
||||||
|
Connection c = DriverManager.getConnection(DB_URL); Statement s = c.createStatement()) {
|
||||||
|
|
||||||
|
s.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS binary_event (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
value INTEGER NOT NULL,
|
||||||
|
timestamp DATETIME NOT NULL
|
||||||
|
)
|
||||||
|
""");
|
||||||
|
|
||||||
|
Logger.info("DB", "Datenbank initialisiert");
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
Logger.error("DB", "Datenbank initialisierung fehlgeschlagen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void store(int value) {
|
||||||
|
try (Connection c = DriverManager.getConnection(DB_URL); PreparedStatement ps = c.prepareStatement("INSERT INTO binary_event (value, timestamp) VALUES (?, ?)")) {
|
||||||
|
ps.setInt(1, value);
|
||||||
|
ps.setString(2, LocalDateTime.now().toString());
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
Logger.error("DB", "Database Insert fehlgeschlagen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||||
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||||
|
*/
|
||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.model.AppState;
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.model.ProblemLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class EvaluationService {
|
||||||
|
|
||||||
|
private final StatisticsService statisticsService;
|
||||||
|
private final AppState appState;
|
||||||
|
private final UnrealWebSocketService unrealService;
|
||||||
|
|
||||||
|
public EvaluationService(
|
||||||
|
StatisticsService statisticsService,
|
||||||
|
AppState appState,
|
||||||
|
UnrealWebSocketService unrealService
|
||||||
|
) {
|
||||||
|
|
||||||
|
this.statisticsService = statisticsService;
|
||||||
|
this.appState = appState;
|
||||||
|
this.unrealService = unrealService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluate() {
|
||||||
|
double ratio = statisticsService.getRatio(10);
|
||||||
|
|
||||||
|
ProblemLevel level;
|
||||||
|
|
||||||
|
if (ratio >= 0.9) {
|
||||||
|
level = ProblemLevel.DISASTER;
|
||||||
|
} else if (ratio >= 0.8) {
|
||||||
|
level = ProblemLevel.HIGH;
|
||||||
|
} else if (ratio >= 0.5) {
|
||||||
|
level = ProblemLevel.WARNING;
|
||||||
|
} else {
|
||||||
|
level = ProblemLevel.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level != appState.getProblemLevel()) {
|
||||||
|
appState.setProblemLevel(level);
|
||||||
|
unrealService.speak(level.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package efi.projekt.virtueller_gesundheitsassistent.service;
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
import efi.projekt.virtueller_gesundheitsassistent.model.AssistantState;
|
import efi.projekt.virtueller_gesundheitsassistent.model.AppState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -8,11 +8,11 @@ import efi.projekt.virtueller_gesundheitsassistent.model.AssistantState;
|
|||||||
*/
|
*/
|
||||||
public class StateService {
|
public class StateService {
|
||||||
|
|
||||||
private static final AssistantState STATE = new AssistantState();
|
private static final AppState STATE = new AppState();
|
||||||
|
|
||||||
private StateService() {}
|
private StateService() {}
|
||||||
|
|
||||||
public static AssistantState getState() {
|
public static AppState getState() {
|
||||||
return STATE;
|
return STATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||||
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||||
|
*/
|
||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.util.Logger;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class StatisticsService {
|
||||||
|
|
||||||
|
private static final String DB_URL = "jdbc:sqlite:data/health.db";
|
||||||
|
|
||||||
|
public double getRatio(int lastN) {
|
||||||
|
String query = """
|
||||||
|
SELECT AVG(value)
|
||||||
|
FROM (
|
||||||
|
SELECT value
|
||||||
|
FROM binary_event
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
LIMIT ?
|
||||||
|
)
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (Connection c = DriverManager.getConnection(DB_URL); PreparedStatement ps = c.prepareStatement(query)) {
|
||||||
|
ps.setInt(1, lastN);
|
||||||
|
|
||||||
|
ResultSet rs = ps.executeQuery();
|
||||||
|
if (rs.next()) {
|
||||||
|
return rs.getDouble(1);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
Logger.error("Evaluation", "Couldn't get ratio.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ module efi.projekt.virtueller_gesundheitsassistent {
|
|||||||
requires javafx.web;
|
requires javafx.web;
|
||||||
requires jakarta.websocket.client;
|
requires jakarta.websocket.client;
|
||||||
requires opencv;
|
requires opencv;
|
||||||
|
requires java.sql;
|
||||||
|
|
||||||
|
|
||||||
opens efi.projekt.virtueller_gesundheitsassistent to javafx.fxml;
|
opens efi.projekt.virtueller_gesundheitsassistent to javafx.fxml;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user