SEPIA-Framework / sepia-docs

Documentation and Wiki for SEPIA. Please post your questions and bug-reports here in the issues section! Thank you :-)
https://sepia-framework.github.io/
238 stars 16 forks source link

Anbindung an Individualsystem #29

Closed Praevision closed 4 years ago

Praevision commented 4 years ago

Vielen Dank erstmal für die großartige Arbeit, ich habe SEPIA recht einfach zum Laufen bekommen. Allerdings ist mir nicht ganz klar, wie ich mein SmartHome (komplette Eigenentwicklung) anbinden kann. Wenn ich z. B. sage "Stelle Heizung im Wohnzimmer auf 23 Grad" sollte am besten per MQTT an meinen Broker eine Nachricht mit den entsprechend erkannten Attributen rausgehen. Ich habe bei den Extensions etwas mit MQTT gefunden, mir ist aber nicht ganz klar, wie ich das so verwende, dass es bei jedem Erkannten SmartHome-Befehl die MQTT raus schickt. Ist das überhaupt machbar? Wäre für Hilfe hierbei sehr dankbar :)

fquirin commented 4 years ago

Hi,

ja, dieses Thema kam in letzter Zeit öfters auf und der MQTT Demo im Extensions Repo ist eine Möglichkeit, wie man es machen kann. Wie der Name allerdings sagt ist das ein "Demo", heißt es ist so konfiguriert, dass alle Sätze die mit "Mqtt" anfangen oder aufhören mit der Smart-Home NLU verarbeitet und an den MQTT-Broker geschickt werden. Wie man diesen Service aktiviert steht hier in der Sektion "Code-UI" (Hinweise am Anfang beachten bzgl. "enable SDK"). In dem Code-Interface kannst du dann den MQTT Demo laden und auch die Broker URL am Anfang leicht editieren.

Wenn du diesen Weg ausprobieren willst helfe ich gerne mit den Details weiter :slightly_smiling_face: , man kann den Trigger (MQTT am Anfang/Ende) natürlich auch anpassen u.v.m..

Parallel arbeite ich an einem neuen Modul, dass MQTT ganz allgemein als "Smart Home HUB" Interface einbaut. Das wird aber noch ein paar Tage dauern, da ich eine neue Option schaffe Geräte in der SEPIA Datenbank zu verwalten (das hatten bisher die anderen HUBs wie FHEM oder OpenHAB übernommen). Ich sage mal ich bin zuversichtlich, dass das diesen Monat fertig wird :-)

Praevision commented 4 years ago

Danke für die schnelle Antwort. Ich habe mal die MQTT Demo als Template genommen, die Broker-IP geändert und hochgeladen. Einiges ist mir aber nicht ganz klar:

Edit: Ich hab die Abfrage nach dem Gerät mal rausgenommen, jetzt bekomme ich als Antwort immer, dass etwas schief gegangen ist ;/

public class MqttInterface implements ServiceInterface {

    //Command name of your service (will be combined with userId to be unique, e.g. 'uid1007.mqtt')
    private static final String CMD_NAME = "mqtt";

    //MQTT broker address
    private String mqttBroker = "localhost:1883";       //public test broker
    private String mqttUserName = "";
    private String mqttPassword = "";

    @Override
    public ServiceRequirements getRequirements(){
        return new ServiceRequirements()
            .serverMinVersion("2.4.0")
        ;
    }

    //Define some sentences for testing:

    @Override
    public TreeSet<String> getSampleSentences(String lang) {
        TreeSet<String> samples = new TreeSet<>();
        //GERMAN
        if (lang.equals(Language.DE.toValue())){
            samples.add("MQTT testen.");
        //OTHER
        }else{
            samples.add("Test MQTT.");
        }
        return samples;
    }

    //Basic service setup:

    //Overriding the 'getAnswersPool' methods enables you to define custom answers with more complex features.
    //You can build a pool of answers that can have multiple versions of the same answer used for different 
    //situations like a repeated question (what was the time? -> sorry say again, what was the time? -> ...).

    @Override
    public ServiceAnswers getAnswersPool(String language) {
        ServiceAnswers answerPool = new ServiceAnswers(language);

        //Build German answers
        if (language.equals(LANGUAGES.DE)){
            answerPool
                .addAnswer(successAnswer,   0, "Nachricht wurde gesendet.")
                .addAnswer(okAnswer,        0, "Die Anfrage ist angekommen aber ich kann sie nicht bearbeiten.")
            ;
            return answerPool;

        //Or default to English
        }else{
            answerPool  
                .addAnswer(successAnswer,   0, "Message has been broadcasted.")
                .addAnswer(okAnswer,        0, "Message received but I could not fulfill your request.")
            ;
            return answerPool;
        }
    }
    //We keep a reference here for easy access in getResult - Note that custom answers start with a specific prefix, the system answers don't.
    private static final String successAnswer = ServiceAnswers.ANS_PREFIX + CMD_NAME + "_success_0a";
    private static final String okAnswer = ServiceAnswers.ANS_PREFIX + CMD_NAME + "_still_ok_0a";
    private static final String failAnswer = "error_0a";
    private static final String notAllowed = "smartdevice_0d";

    //Basic service setup:

    @Override
    public ServiceInfo getInfo(String language) {
        //Type of service (for descriptions, choose what you think fits best)
        ServiceInfo info = new ServiceInfo(Type.otherAPI, Content.data, false);

        //Should be available publicly or only for the developer? Set this when you are done with testing and want to release.
        //NOTE: only services uploaded by the assistant account (default ID: uid1005) can be public for all users.
        info.makePublic();

        //Command
        info.setIntendedCommand(Sdk.getMyCommandName(this, CMD_NAME));

        //Direct-match trigger sentences in different languages
        String EN = Language.EN.toValue();
        info.addCustomTriggerSentenceWithExtractedParameters("Test MQTT.", EN, JSON.make(
                PARAMETERS.SMART_DEVICE,    SmartDevice.getExtractedValueFromType(SmartDevice.Types.device, "MQTT Client"),
                PARAMETERS.ACTION,          Action.getExtractedValueFromType(Action.Type.on)
        ));
        String DE = Language.DE.toValue();
        info.addCustomTriggerSentenceWithExtractedParameters("MQTT testen.", DE, JSON.make(
                PARAMETERS.SMART_DEVICE,    SmartDevice.getExtractedValueFromType(SmartDevice.Types.device, "MQTT Client"),
                PARAMETERS.ACTION,          Action.getExtractedValueFromType(Action.Type.on)
        ));

        //Regular expression triggers
        //NOTE: use 'normalized' text here, e.g. lower-case and no special characters ?, !, ., ', etc. ... for ä, ö, ü, ß, ... use ae, oe, ue, ss, ...
        info.setCustomTriggerRegX("^(mqtt)\\b.*|.*\\b(mqtt)$", EN);
        info.setCustomTriggerRegX("^(mqtt)\\b.*|.*\\b(mqtt)$", DE);
        info.setCustomTriggerRegXscoreBoost(10);        //boost service to increase priority over similar ones

        //Parameters:

        //Required parameters will be asked automatically by SEPIA using the defined question.
        Parameter p1 = new Parameter(PARAMETERS.SMART_DEVICE)
                .setRequired(true)
                .setQuestion("smartdevice_1a")      //note: question defined by system
        ;
        //info.addParameter(p1);

        //Optional parameters will be set if found or ignored (no question, default value)
        Parameter p2 = new Parameter(PARAMETERS.ACTION, Action.Type.toggle);    //toggle seems to be the most reasonable default action "lights" -> "light on"
        Parameter p3 = new Parameter(PARAMETERS.SMART_DEVICE_VALUE, "");
        Parameter p4 = new Parameter(PARAMETERS.ROOM, "");
        info.addParameter(p2).addParameter(p3).addParameter(p4);

        //Answers (these are the default answers, you can trigger a custom answer at any point in the module 
        //with serviceBuilder.setCustomAnswer(..)):
        info.addSuccessAnswer(successAnswer)
            .addFailAnswer(failAnswer)
            .addOkayAnswer(okAnswer)
            //.addCustomAnswer("setState", deviceStateSet)  //adding these answers here is optional and used just as info
            //.addCustomAnswer("showState", deviceStateShow)
            //.addCustomAnswer("askStateValue", askStateValue)
            .addCustomAnswer("notAllowed", notAllowed)
        ;

        //Add answer parameters that are used to replace <1>, <2>, ... in your answers.
        //The name is arbitrary but you need to use the same one in getResult(...) later for api.resultInfoPut(...)
        //info.addAnswerParameters("device_name", "device_value");  //<1>=..., <2>=...

        return info;
    }

    @Override
    public ServiceResult getResult(NluResult nluResult) {
        //initialize result
        ServiceBuilder service = new ServiceBuilder(nluResult, 
                getInfoFreshOrCache(nluResult.input, this.getClass().getCanonicalName()),
                getAnswersPool(nluResult.language));

        //check user role 'smarthomeguest' for this service (because it can control devices in the server's network)
        if (!nluResult.input.user.hasRole(Role.smarthomeguest)){
            service.setStatusOkay();
            service.setCustomAnswer(notAllowed);            //"soft"-fail with "not allowed" answer
            return service.buildResult();
        }

        //get required parameters
        //Parameter device = nluResult.getRequiredParameter(PARAMETERS.SMART_DEVICE);
        //get optional parameters
        Parameter action = nluResult.getOptionalParameter(PARAMETERS.ACTION, "");
        Parameter deviceValue = nluResult.getOptionalParameter(PARAMETERS.SMART_DEVICE_VALUE, "");
        Parameter room = nluResult.getOptionalParameter(PARAMETERS.ROOM, "");

        //----Evaluate---

        //String deviceType = device.getValueAsString();    //shortcut for: JSON.getString(device.getData(), InterviewData.VALUE)
        //String deviceName = JSON.getStringOrDefault(device.getData(), InterviewData.FOUND, "");
        //String deviceTypeLocal = JSON.getStringOrDefault(device.getData(), InterviewData.VALUE_LOCAL, deviceType);
        //int deviceNumber = JSON.getIntegerOrDefault(device.getData(), InterviewData.ITEM_INDEX, Integer.MIN_VALUE);

        String roomType = room.getValueAsString().replaceAll("^<|>$", "").trim();       //... this is actually already without <..>
        //String roomTypeLocal = JSON.getStringOrDefault(room.getData(), InterviewData.VALUE_LOCAL, roomType);
        int roomNumber = JSON.getIntegerOrDefault(room.getData(), InterviewData.ITEM_INDEX, Integer.MIN_VALUE);

        String actionType = action.getValueAsString().replaceAll("^<|>$", "").trim();   //TODO: fix inconsistency in parameter format for device and room

        String targetSetValue = deviceValue.getValueAsString();
        String targetValueType = JSON.getStringOrDefault(deviceValue.getData(), 
                InterviewData.SMART_DEVICE_VALUE_TYPE, SmartHomeDevice.StateType.number_plain.name());

        //SHOW
        //if (Is.typeEqual(actionType, Action.Type.show)){
        //  //TODO: we cannot show, because we can't read MQTT data in this example (only broadcast).
        //  service.setStatusOkay();            //"soft"-fail (action not possible)
        //  return service.buildResult();

        //Broadcast other actions
        //}else{
        //connect to MQTT broker, build message, broadcast
        try
        {
            SepiaMqttClientOptions mqttOptions = new SepiaMqttClientOptions()
                    .setAutomaticReconnect(false)
                    .setCleanSession(true)
                    .setConnectionTimeout(6);
            if (Is.notNullOrEmpty(this.mqttUserName)){
                mqttOptions.setUserName(this.mqttUserName);
            }
            if (Is.notNullOrEmpty(this.mqttPassword)){
                mqttOptions.setPassword(this.mqttPassword);
            }
            SepiaMqttClient mqttClient = new SepiaMqttClient(mqttBroker, mqttOptions);
            mqttClient.connect();
            mqttClient.publish("sepia/mqtt-demo", new SepiaMqttMessage(JSON.make(
                    "payload", "Testinhalt",
                    "roomType", roomType,
                    "roomIndex", (roomNumber == Integer.MIN_VALUE)? "" : String.valueOf(roomNumber),
                    "action", JSON.make(
                        "type", actionType,
                        "value", targetSetValue,
                        "valueType", targetValueType
                    )
            ).toJSONString())
                    .setQos(0)
                    .setRetained(false)
            );
            mqttClient.disconnect();
            mqttClient.close();

        }catch (Exception e){
            //ERROR
            e.printStackTrace();
            //fail answer
            service.setStatusFail();            //"hard"-fail (probably connection error)
            return service.buildResult();
        }
        //}

        //---------------

        //Just for demo purposes we add a button-action with a link to the SDK
        service.addAction(ACTIONS.BUTTON_IN_APP_BROWSER);
        service.putActionInfo("url", "https://github.com/SEPIA-Framework/sepia-sdk-java");
        service.putActionInfo("title", "SDK info");

        //... and we also add a demo card that points to the SEPIA homepage
        Card card = new Card(Card.TYPE_SINGLE);
        JSONObject linkCard = card.addElement(
                ElementType.link, 
                JSON.make("title", "S.E.P.I.A." + ":", "desc", "Homepage"),
                null, null, "", 
                "https://sepia-framework.github.io/", 
                "https://sepia-framework.github.io/img/icon.png", 
                null, null
        );
        JSON.put(linkCard, "imageBackground", "#000");  //more options like CSS background
        service.addCard(card.getJSON());

        //build the API_Result
        service.setStatusSuccess();
        ServiceResult result = service.buildResult();
        return result;
    }
}
fquirin commented 4 years ago

Wenn ich im Code-UI den Code hochlade, wo kann ich den wieder finden ...

Der Code wird beim Hochladen in eine Java Klasse kompiliert. Diese liegt im Ordner Xtensions/Plugins/... des Assist-Servers. Leider kann man die Datei von dort nicht wieder einlesen. Momentan sollte man am besten immer eine Kopie des eigenen, geänderten Codes irgendwo Ablegen. Ist noch etwas unhandlich, ich weiß :see_no_evil:. Mit dem SEPIA Java SDK geht es etwas leichter, dazu braucht man aber eine IDE wie den Eclipse Editor.

... und wie kann ich ihn in der Teach-UI auswählen?

Über den Befehl 'Execute Command(s)'. Willst du zB den "Licht" Befehl über den MQTT Demo publizieren könnte der Satz so aussehen "Licht" und bei 'Execute Command(s)' -> "mqtt Licht im Wohnzimmer auf 70%".

Wenn ich an Sepia z. B. "Test MQTT" sende, fragt er nach einem Gerät. Gebe ich "MQTT Client" ein, dann versteht er das nicht. Ich will ja an sich gar nicht die Geräte direkt ansteuern, sondern nur erkannte Befehle an den Broker weitersenden.

Services in SEPIA sind immer zielorientiert. Ziele werden in der Sektion public ServiceInfo getInfo(...) definiert unter 'required' und 'optional' parameters. Der MQTT Demo in dem Fall hat das Ziel:

//Required parameters will be asked automatically by SEPIA using the defined question.
Parameter p1 = new Parameter(PARAMETERS.SMART_DEVICE)
        .setRequired(true)

Er versucht also ein Smart-Home Gerät zu finden und das dann über den MQTT Broker zu senden.

Du könntest diesen Parameter verschieben in die "optional" Sektion, z.B. so:

Parameter p1 = new Parameter(PARAMETERS.SMART_DEVICE, "")

Dann wird der Service keine Frage mehr stellen und alles senden was er findet zu den optionalen Parametern, also z.B. "Licht", "Wohnzimmer" etc..

Praevision commented 4 years ago

Parameter p1 = new Parameter(PARAMETERS.SMART_DEVICE, "")

Wenn ich das mache wie du es vorgeschlagen hast, kriege ich trotzdem einen Fehler:

{
  "result": "still_ok",
  "hasAction": false,
  "cardInfo": [],
  "answer": "Sorry, da gab es wohl einen Fehler. Versuch es doch noch mal bitte.",
  "more": {
    "certainty_lvl": 0.44,
    "cmd_summary": "uid1007.SmartHome;;smart_device={\"value_local\":\"das Licht\",\"device_tag\":\"Licht\",\"value\":\"light\"};;action={\"value_local\":\"anschalten\",\"value\":\"<on>\"};;smart_device_value=;;room={\"value_local\":\"im Wohnzimmer\",\"room_tag\":\"Wohnzimmer\",\"value\":\"livingroom\"};;",
    "context": "uid1007.SmartHome;;default",
    "language": "de",
    "user": "uid1007"
  },
  "hasCard": false,
  "actionInfo": [],
  "answer_clean": "Sorry, da gab es wohl einen Fehler. Versuch es doch noch mal bitte.",
  "htmlInfo": "",
  "hasInfo": false,
  "resultInfo": {
    "device_name": "",
    "device_value": "",
    "cmd": "uid1007.SmartHome"
  }
}
fquirin commented 4 years ago

Hmmmmm :thinking: , steht in der log.out vom SEPIA Assist Server mehr über den Fehler? (~/SEPIA/sepia-assist-server/)

Praevision commented 4 years ago

Scheint wohl am Verbindungsaufbau zum MQTT-Server zu liegen. Eine Authentifizierung o. ä. ist bei meinem Broker nicht notwendig.

Wenn ich als URI ws://127.0.0.1:1883 nehme bekomme ich folgende Fehler ((~/SEPIA/sepia-assist-server/log.out):

2020-04-06 20:24:40 LOG - USER uid1007 used SERVICE uid1007.SmartHome - TS: 1586197480550 - LANGUAGE: de - CLIENT: web_app_tools - API: v2.4.1
MqttException (0) - java.net.SocketException: Connection reset
        at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
        at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:715)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.net.SocketException: Connection reset
        at java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
        at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
        at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
        at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
        at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
        at java.base/java.io.InputStreamReader.read(InputStreamReader.java:185)
        at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
        at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
        at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
        at org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketHandshake.receiveHandshakeResponse(WebSocketHandshake.java:131)
        at org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketHandshake.execute(WebSocketHandshake.java:76)
        at org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketNetworkModule.start(WebSocketNetworkModule.java:64)
        at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:701)

Beim Broker (Mosquitto) bekomme ich folgende Meldung:

1586197979: New connection from 127.0.0.1 on port 1883.
1586197979: Socket error on client <unknown>, disconnecting.

Wenn ich ws:// weg lasse kommt folgende Fehlermeldung:

2020-04-06 19:05:29 LOG - USER uid1007 used SERVICE uid1007.SmartHome - TS: 1586192729129 - LANGUAGE: de - CLIENT: web_app_tools - API: v2.4.1
java.lang.IllegalArgumentException: 127.0.0.1:1883
        at org.eclipse.paho.client.mqttv3.MqttConnectOptions.validateURI(MqttConnectOptions.java:555)
        at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:463)
        at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:328)
        at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:323)
        at org.eclipse.paho.client.mqttv3.MqttClient.<init>(MqttClient.java:229)
        at net.b07z.sepia.websockets.mqtt.SepiaMqttClient.<init>(SepiaMqttClient.java:42)
        at net.b07z.sepia.sdk.services.uid1007.MqttInterface.getResult(MqttInterface.java:226)
        at net.b07z.sepia.server.assist.interviews.Interview.getServiceResults(Interview.java:193)
        at net.b07z.sepia.server.assist.interviews.AbstractInterview.getServiceResults(AbstractInterview.java:200)
        at net.b07z.sepia.server.assist.endpoints.AssistEndpoint.answerAPI(AssistEndpoint.java:343)
        at net.b07z.sepia.server.assist.server.Start.lambda$loadEndpoints$15(Start.java:324)
        at spark.RouteImpl$1.handle(RouteImpl.java:72)
        at spark.http.matching.Routes.execute(Routes.java:61)
        at spark.http.matching.MatcherFilter.doFilter(MatcherFilter.java:134)
        at spark.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:50)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1671)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.eclipse.jetty.server.Server.handle(Server.java:505)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
        at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:698)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:804)
        at java.base/java.lang.Thread.run(Thread.java:834)
fquirin commented 4 years ago

Wenn ich als URI ws://127.0.0.1:1883 nehme bekomme ich folgende Fehler (~/SEPIA/sepia-assist-server/log.out): [...]

Der Fehler ist irgendwie so nichtssagend :-( Den Grund für "Connection Reset" kann ich da nicht erkennen.

Hat der MQTT Broadcast denn schon mal funktioniert? Falls nicht, kannst du es noch mal mit der originalen Version versuchen? (nur deine Broker URL anpassen, als Satz müsste sowas wie "mqtt Licht im Wohnzimmer" oder "Licht im Wohnzimmer via MQTT" funktionieren). Eventuell auch mal einfach bei 'mqttUserName' und Passwort irgendwas beliebiges eingeben, manche Broker haben wohl Probleme mit anonymous.

Welchen MQTT Broker nutzt du?

Wenn ich ws:// weg lasse kommt folgende Fehlermeldung:[...]

Das ws:// muss auf jeden Fall da bleiben.

Praevision commented 4 years ago

Mit dem originalen MQTTDemo bekomme ich den gleichen Fehler, auch wenn ich Dummy-Usernamen und/oder Passwort vergebe. Als Broker verwende ich Mosquitto. Der Broker funktioniert bei 15 anderen Teilnehmern (ESPs, Python-MQTT-Clients) sowohl lokal als auch vom Netzwerk aus eigentlich einwandfrei, seis mit oder ohne Usename. Was mich etwas stutzig macht ist die Fehlermeldung vom Broker "Socket error on client unknown, disconnecting.". Eventuell mag der Broker nicht, dass der Client keine ID mitgibt. Da ich mich in Java leider nur sehr wenig auskenne, weiß ich nicht, wo ich das einfügen könnte, dass SEPIA eine Client-ID beim connecten übergibt.

fquirin commented 4 years ago

Da ich mich in Java leider nur sehr wenig auskenne, weiß ich nicht, wo ich das einfügen könnte, dass SEPIA eine Client-ID beim connecten übergibt.

Das war auch mein erster Gedanke, aber ich hatte das noch mal überprüft. Die Client ID wird über den Constructor SepiaMqttClientOptions mqttOptions = new SepiaMqttClientOptions(ID or nothing) gesetzt. Wenn keine ID mitgegeben wird, wird eine zufällige erstellt. Du könntest hier ja mal was eigenes eingeben, aber bei mir war das bisher kein Problem. Ich nutze ebenfalls Mosquitto (v1.6.9) für alle Tests :thinking:

Praevision commented 4 years ago

Also ich habe den Broker jetzt mal auf 1.6.9 (war vorher 1.4.1X) upgedatet, die ID im Constructor festgelegt und den 8000er Port wie in dem Beispiel verwendet. Ich bekomme aber in der Sepia-Log immer noch den gleichen Fehler angezeigt, nur der Broker zeigt jetzt einen anderen Fehler:


1586330403: New connection from 192.168.0.23 on port 8000.
1586330403: Client <unknown> disconnected due to **protocol error.**
fquirin commented 4 years ago

Ein Fortschritt ^^. Morgen gucke ich es mir noch mal genauer an :crossed_fingers:

fquirin commented 4 years ago

Ein neuer Tag, eine neue Erkenntnis ^^. Sieht so aus als wäre mein Mosquitto für WebSocket konfiguriert gewesen, was aber nicht Standard ist. Versuch mal: tcp://localhost:1883 bzw tcp://192.168.0.23:8000 (je nachdem was deine URL ist) :-)

Praevision commented 4 years ago

jaaaa das war der springende Punkt, jetzt funktioniert es hervorragend :) Vielen Dank!

Komisch aber, dass es nicht trotzdem funktioniert hat. Ich habe nämlich bei dem Update von Mosquitto auf 1.6.9 WebSocket auch mitkompiliert.

fquirin commented 4 years ago

Komisch aber, dass es nicht trotzdem funktioniert hat. Ich habe nämlich bei dem Update von Mosquitto auf 1.6.9 WebSocket auch mitkompiliert.

Ja, ich hatte mir auch noch mal ne neue 1.6.9er gesaugt und es trotz angeblich eingebauter WS Unterstützung nicht zum laufen bekommen :-/ Angeblich soll man in der Config folgendes eintragen:

listener 8001
protocol websockets

Und dann beim Start darauf achten, dass die Config auch geladen wird: mosquitto -c mosquitto.conf. Funktioniert bei mir aber nicht.