Changes due to new requirements
This commit is contained in:
commit
5b072329d3
40
nbactions.xml
Normal file
40
nbactions.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<actions>
|
||||||
|
<action>
|
||||||
|
<actionName>run</actionName>
|
||||||
|
<packagings>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
</packagings>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
<goal>javafx:run</goal>
|
||||||
|
</goals>
|
||||||
|
</action>
|
||||||
|
<action>
|
||||||
|
<actionName>debug</actionName>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
<goal>javafx:run@ide-debug</goal>
|
||||||
|
</goals>
|
||||||
|
<properties>
|
||||||
|
<jpda.listen>true</jpda.listen>
|
||||||
|
</properties>
|
||||||
|
</action>
|
||||||
|
<action>
|
||||||
|
<actionName>profile</actionName>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
<goal>javafx:run@ide-profile</goal>
|
||||||
|
</goals>
|
||||||
|
</action>
|
||||||
|
<action>
|
||||||
|
<actionName>CUSTOM-jlink</actionName>
|
||||||
|
<displayName>jlink</displayName>
|
||||||
|
<goals>
|
||||||
|
<goal>clean</goal>
|
||||||
|
<!-- compile not needed with javafx-maven-plugin v0.0.5 -->
|
||||||
|
<goal>compile</goal>
|
||||||
|
<goal>javafx:jlink</goal>
|
||||||
|
</goals>
|
||||||
|
</action>
|
||||||
|
</actions>
|
||||||
106
pom.xml
Normal file
106
pom.xml
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>efi.projekt</groupId>
|
||||||
|
<artifactId>Virtueller_Gesundheitsassistent</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-controls</artifactId>
|
||||||
|
<version>13</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.paho</groupId>
|
||||||
|
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||||
|
<version>1.2.5</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-web</artifactId>
|
||||||
|
<version>21.0.9</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-fxml</artifactId>
|
||||||
|
<version>21.0.9</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.websocket</groupId>
|
||||||
|
<artifactId>jakarta.websocket-client-api</artifactId>
|
||||||
|
<version>2.2.0</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openpnp</groupId>
|
||||||
|
<artifactId>opencv</artifactId>
|
||||||
|
<version>4.12.0</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>21</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-maven-plugin</artifactId>
|
||||||
|
<version>0.0.4</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>efi.projekt.virtueller_gesundheitsassistent.App</mainClass>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<!-- Default configuration for running -->
|
||||||
|
<!-- Usage: mvn clean javafx:run -->
|
||||||
|
<id>default-cli</id>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<!-- Configuration for manual attach debugging -->
|
||||||
|
<!-- Usage: mvn clean javafx:run@debug -->
|
||||||
|
<id>debug</id>
|
||||||
|
<configuration>
|
||||||
|
<options>
|
||||||
|
<option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000</option>
|
||||||
|
</options>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<!-- Configuration for automatic IDE debugging -->
|
||||||
|
<id>ide-debug</id>
|
||||||
|
<configuration>
|
||||||
|
<options>
|
||||||
|
<option>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</option>
|
||||||
|
</options>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<!-- Configuration for automatic IDE profiling -->
|
||||||
|
<id>ide-profile</id>
|
||||||
|
<configuration>
|
||||||
|
<options>
|
||||||
|
<option>${profiler.jvmargs.arg1}</option>
|
||||||
|
<option>${profiler.jvmargs.arg2}</option>
|
||||||
|
<option>${profiler.jvmargs.arg3}</option>
|
||||||
|
<option>${profiler.jvmargs.arg4}</option>
|
||||||
|
<option>${profiler.jvmargs.arg5}</option>
|
||||||
|
</options>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import static javafx.application.Application.launch;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JavaFX App
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class App extends Application {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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
|
||||||
|
|
||||||
|
Scene scene = new Scene(root, 1280, 720);
|
||||||
|
|
||||||
|
primaryStage.setTitle("Virtueller Gesundheitsassistent");
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Parent loadFXML(String fxml) throws IOException {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
|
App.class.getResource("/efi/projekt/virtueller_gesundheitsassistent/view/" + fxml + ".fxml")
|
||||||
|
);
|
||||||
|
return fxmlLoader.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
launch();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent;
|
||||||
|
|
||||||
|
public class SystemInfo {
|
||||||
|
|
||||||
|
public static String javaVersion() {
|
||||||
|
return System.getProperty("java.version");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String javafxVersion() {
|
||||||
|
return System.getProperty("javafx.version");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.controller;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.service.CameraService;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class CameraController {
|
||||||
|
|
||||||
|
@FXML private ImageView cameraView;
|
||||||
|
|
||||||
|
private final CameraService cameraService = new CameraService();
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void initialize() {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void start() {
|
||||||
|
cameraService.start(image ->
|
||||||
|
Platform.runLater(() -> cameraView.setImage(image))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void stopCamera() {
|
||||||
|
cameraService.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public record Classification (
|
||||||
|
String label,
|
||||||
|
String text,
|
||||||
|
String mqttValue
|
||||||
|
) {}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public enum ClassificationType {
|
||||||
|
NORMAL,
|
||||||
|
MUEDIGKEIT,
|
||||||
|
ABLENKUNG,
|
||||||
|
STRESS,
|
||||||
|
REAKTION
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.util.Logger;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.MatOfByte;
|
||||||
|
import org.opencv.imgcodecs.Imgcodecs;
|
||||||
|
import org.opencv.videoio.VideoCapture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class CameraService {
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VideoCapture capture;
|
||||||
|
private ScheduledExecutorService timer;
|
||||||
|
|
||||||
|
public void start(java.util.function.Consumer<Image> frameConsumer) {
|
||||||
|
if (capture != null && capture.isOpened()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
capture = new VideoCapture(0);
|
||||||
|
|
||||||
|
if (!capture.isOpened()) {
|
||||||
|
Logger.error("CAMERA", "Kamera konnte nicht geoeffnet werden");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Runnable frameGrabber = () -> {
|
||||||
|
Mat frame = new Mat();
|
||||||
|
if (capture.read(frame)) {
|
||||||
|
Image image = matToImage(frame);
|
||||||
|
frameConsumer.accept(image);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
timer = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
Logger.info("CAMERA", "Kamera gestartet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (timer != null && !timer.isShutdown()) {
|
||||||
|
timer.shutdown();
|
||||||
|
}
|
||||||
|
if (capture != null && capture.isOpened()) {
|
||||||
|
capture.release();
|
||||||
|
}
|
||||||
|
Logger.info("CAMERA", "Kamera gestoppt");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Image matToImage(Mat frame) {
|
||||||
|
MatOfByte buffer = new MatOfByte();
|
||||||
|
Imgcodecs.imencode(".png", frame, buffer);
|
||||||
|
return new Image(new ByteArrayInputStream(buffer.toArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
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,121 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.util.Logger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import org.eclipse.paho.client.mqttv3.*;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class MqttClientService implements MqttCallback {
|
||||||
|
|
||||||
|
private static final String BROKER_URL = "tcp://localhost:1883";
|
||||||
|
private static final String CLIENT_ID = "JavaClientPublisherSubscriber";
|
||||||
|
|
||||||
|
private final Map<String, Consumer<String>> topicListeners =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private MqttClient client;
|
||||||
|
|
||||||
|
public MqttClientService() {
|
||||||
|
try {
|
||||||
|
client = new MqttClient(
|
||||||
|
BROKER_URL,
|
||||||
|
CLIENT_ID,
|
||||||
|
new MemoryPersistence()
|
||||||
|
);
|
||||||
|
client.setCallback(this);
|
||||||
|
|
||||||
|
MqttConnectOptions options = new MqttConnectOptions();
|
||||||
|
options.setCleanSession(true);
|
||||||
|
options.setAutomaticReconnect(true);
|
||||||
|
|
||||||
|
Logger.info("MQTT", "Verbinde mit Broker " + BROKER_URL);
|
||||||
|
client.connect(options);
|
||||||
|
Logger.info("MQTT", "Verbindung hergestellt");
|
||||||
|
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Logger.error("MQTT", "Fehler beim Verbinden", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
try {
|
||||||
|
if (client != null && client.isConnected()) {
|
||||||
|
client.disconnect();
|
||||||
|
Logger.info("MQTT", "Verbindung getrennt");
|
||||||
|
}
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Logger.error("MQTT", "Fehler beim Trennen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(String topic, Consumer<String> listener) {
|
||||||
|
topicListeners.put(topic, listener);
|
||||||
|
try {
|
||||||
|
client.subscribe(topic);
|
||||||
|
Logger.info("MQTT", "Topic abonniert: " + topic);
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Logger.error("MQTT", "Subscribe fehlgeschlagen: " + topic, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publish(String topic, String message, int qos) {
|
||||||
|
try {
|
||||||
|
MqttMessage mqttMessage =
|
||||||
|
new MqttMessage(message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
mqttMessage.setQos(qos);
|
||||||
|
|
||||||
|
client.publish(topic, mqttMessage);
|
||||||
|
|
||||||
|
Logger.debug(
|
||||||
|
"MQTT",
|
||||||
|
"Publish -> Topic=" + topic + ", QoS=" + qos + ", Payload=" + message
|
||||||
|
);
|
||||||
|
} catch (MqttException e) {
|
||||||
|
Logger.error("MQTT", "Publish fehlgeschlagen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionLost(Throwable cause) {
|
||||||
|
Logger.warn(
|
||||||
|
"MQTT",
|
||||||
|
"Verbindung verloren: " + cause.getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||||
|
String payload =
|
||||||
|
new String(message.getPayload(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
Logger.debug(
|
||||||
|
"MQTT",
|
||||||
|
"Nachricht empfangen -> Topic=" + topic + ", Payload=" + payload
|
||||||
|
);
|
||||||
|
|
||||||
|
Consumer<String> listener = topicListeners.get(topic);
|
||||||
|
if (listener != null) {
|
||||||
|
listener.accept(payload);
|
||||||
|
} else {
|
||||||
|
Logger.warn(
|
||||||
|
"MQTT",
|
||||||
|
"Keine Listener für Topic: " + topic
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||||
|
Logger.debug(
|
||||||
|
"MQTT",
|
||||||
|
"Delivery complete, MessageId=" + token.getMessageId()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.web.WebView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class PixelStreamingService {
|
||||||
|
private final WebView webView;
|
||||||
|
|
||||||
|
public PixelStreamingService(String url) {
|
||||||
|
webView = new WebView();
|
||||||
|
webView.getEngine().load(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getView() {
|
||||||
|
return webView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
webView.getEngine().reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
webView.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
webView.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.model.AssistantState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class StateService {
|
||||||
|
|
||||||
|
private static final AssistantState STATE = new AssistantState();
|
||||||
|
|
||||||
|
private StateService() {}
|
||||||
|
|
||||||
|
public static AssistantState getState() {
|
||||||
|
return STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.service;
|
||||||
|
|
||||||
|
import efi.projekt.virtueller_gesundheitsassistent.util.Logger;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import jakarta.websocket.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
@ClientEndpoint
|
||||||
|
public class UnrealWebSocketService {
|
||||||
|
|
||||||
|
private Session session;
|
||||||
|
private final URI serverUri;
|
||||||
|
private final AtomicBoolean connected = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
|
||||||
|
public UnrealWebSocketService(String serverUrl) {
|
||||||
|
this.serverUri = URI.create(serverUrl);
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connect() {
|
||||||
|
try {
|
||||||
|
WebSocketContainer container =
|
||||||
|
ContainerProvider.getWebSocketContainer();
|
||||||
|
|
||||||
|
Logger.info("UNREAL", "Verbinde zu " + serverUri);
|
||||||
|
container.connectToServer(this, serverUri);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.error("UNREAL", "WebSocket-Verbindung fehlgeschlagen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return connected.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
try {
|
||||||
|
if (session != null && session.isOpen()) {
|
||||||
|
session.close();
|
||||||
|
Logger.info("UNREAL", "WebSocket-Verbindung geschlossen");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.error("UNREAL", "Fehler beim Schließen der Verbindung", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session) {
|
||||||
|
this.session = session;
|
||||||
|
connected.set(true);
|
||||||
|
Logger.info("UNREAL", "WebSocket verbunden");
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClose
|
||||||
|
public void onClose(Session session, CloseReason reason) {
|
||||||
|
connected.set(false);
|
||||||
|
Logger.warn("UNREAL", "WebSocket geschlossen: " + reason.getReasonPhrase());
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnError
|
||||||
|
public void onError(Session session, Throwable throwable) {
|
||||||
|
connected.set(false);
|
||||||
|
Logger.error("UNREAL", "WebSocket-Fehler", throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnMessage
|
||||||
|
public void onMessage(String message) {
|
||||||
|
Logger.debug("UNREAL", "Nachricht empfangen: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void speak(String text) {
|
||||||
|
if (!connected.get()) {
|
||||||
|
Logger.warn("UNREAL", "Nicht verbunden! Text wird nicht gesendet!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String json = buildSpeakMessage(text);
|
||||||
|
|
||||||
|
session.getAsyncRemote().sendText(json);
|
||||||
|
Logger.info("UNREAL", "Sende Speak-Command: " + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildSpeakMessage(String text) {
|
||||||
|
return "{"
|
||||||
|
+ "\"type\":\"speak\","
|
||||||
|
+ "\"text\":\"" + escape(text) + "\""
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String escape(String text) {
|
||||||
|
return text.replace("\"", "\\\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
package efi.projekt.virtueller_gesundheitsassistent.util;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author naumueller
|
||||||
|
*/
|
||||||
|
public class Logger {
|
||||||
|
public enum Level {
|
||||||
|
DEBUG,
|
||||||
|
INFO,
|
||||||
|
WARN,
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Level currentLevel = Level.DEBUG;
|
||||||
|
|
||||||
|
private static final DateTimeFormatter FORMATTER =
|
||||||
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
private Logger() {
|
||||||
|
// Verhindert Instanziierung
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLevel(Level level) {
|
||||||
|
currentLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void debug(String source, String message) {
|
||||||
|
log(Level.DEBUG, source, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void info(String source, String message) {
|
||||||
|
log(Level.INFO, source, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void warn(String source, String message) {
|
||||||
|
log(Level.WARN, source, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void error(String source, String message) {
|
||||||
|
log(Level.ERROR, source, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void error(String source, String message, Throwable throwable) {
|
||||||
|
log(Level.ERROR, source, message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void log(
|
||||||
|
Level level,
|
||||||
|
String source,
|
||||||
|
String message,
|
||||||
|
Throwable throwable
|
||||||
|
) {
|
||||||
|
// Log-Level filtern
|
||||||
|
if (level.ordinal() < currentLevel.ordinal()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String timestamp = LocalDateTime.now().format(FORMATTER);
|
||||||
|
|
||||||
|
String logLine = String.format(
|
||||||
|
"[%s] [%s] [%s] %s",
|
||||||
|
timestamp,
|
||||||
|
level,
|
||||||
|
source,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
|
||||||
|
if (level == Level.ERROR) {
|
||||||
|
System.err.println(logLine);
|
||||||
|
if (throwable != null) {
|
||||||
|
throwable.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println(logLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.Tab?>
|
||||||
|
<?import javafx.scene.control.TabPane?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
|
||||||
|
|
||||||
|
<TabPane xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
<tabs>
|
||||||
|
<Tab text="Minimal">
|
||||||
|
<fx:include source="designs/MinimalView.fxml"/>
|
||||||
|
</Tab>
|
||||||
|
<Tab text="Immersive">
|
||||||
|
<fx:include source="designs/ImmersiveView.fxml"/>
|
||||||
|
</Tab>
|
||||||
|
<Tab text="Compact">
|
||||||
|
<fx:include source="designs/CompactView.fxml"/>
|
||||||
|
</Tab>
|
||||||
|
<Tab text="Dashboard">
|
||||||
|
<fx:include source="designs/DashboardView.fxml"/>
|
||||||
|
</Tab>
|
||||||
|
</tabs>
|
||||||
|
</TabPane>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
|
||||||
|
</AnchorPane>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.image.ImageView?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
|
||||||
|
|
||||||
|
<StackPane xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="efi.projekt.virtueller_gesundheitsassistent.controller.CameraController">
|
||||||
|
<children>
|
||||||
|
<ImageView fx:id="cameraView" fitHeight="240.0" fitWidth="320.0" pickOnBounds="true" preserveRatio="true" />
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
|
||||||
|
</AnchorPane>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
|
||||||
|
</AnchorPane>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
|
||||||
|
</AnchorPane>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
|
|
||||||
|
</AnchorPane>
|
||||||
14
src/main/java/module-info.java
Normal file
14
src/main/java/module-info.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module efi.projekt.virtueller_gesundheitsassistent {
|
||||||
|
requires javafx.controls;
|
||||||
|
requires javafx.fxml;
|
||||||
|
requires java.base;
|
||||||
|
requires org.eclipse.paho.client.mqttv3;
|
||||||
|
requires javafx.web;
|
||||||
|
requires jakarta.websocket.client;
|
||||||
|
requires opencv;
|
||||||
|
|
||||||
|
|
||||||
|
opens efi.projekt.virtueller_gesundheitsassistent to javafx.fxml;
|
||||||
|
|
||||||
|
exports efi.projekt.virtueller_gesundheitsassistent;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user