lumapu / ahoy

Various tools, examples, and documentation for communicating with Hoymiles microinverters
https://ahoydtu.de
Other
953 stars 224 forks source link

Feature request: connect always to AP with strongest RSSI #611

Closed beegee3 closed 1 year ago

beegee3 commented 1 year ago

zunächst ein Hinweis, wenn man sich nach einem boot/reboot am ESP im AP Modus anmeldet: anders als im STA Modus läuft weiterhin nur die app::loopWifi. Um auf app::loopStandard umzuschalten, ist in ahoywifi::tickWifiLoop nach WiFi.mode(WIFI_AP); noch mAppWifiCb(true); einzufügen. Dann läuft auch im AP Modus alles wie gewünscht (bis auf die Zeit, die man über Web Browser setzen muss, bevor man Live Werte erhält). Allerdings merkt das Programm nicht, wenn man die Verbindung zum AP trennt, da nach dem Callback Aufruf der Wifi Ticker nicht mehr läuft. Entweder man fängt entsprechende 'Station disconnected' Events ab, oder startet einfach den Wifi Ticker in app::onWifi:

    ...
    if (gotIp) {
        ...
        if(WIFI_AP == WiFi.getMode())
            everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
    }
    ...

nun aber der eigentliche Vorschlag, angeregt durch @knickohr in #571. Auch dazu ein paar Worte vorab: wenn man mehrere APs mit derselben SSID hat, wird bisher nicht notwendig mit dem verbunden, der das stärkste RSSI hat, auch wenn die Auswahl bei den Settings in der Web Oberfläche das suggeriert. Allerdings kann man gezielt nach allen APs mit derselben SSID scannen und erhält im Ergebnis u.a. deren BSSID (manchmal auch als MAC des AP bezeichnet). Diese kann man dann beim Verbindungsaufbau mit angeben und so den gewünschten AP auswählen. Die Sache hat nur einen Haken: wenn der AP die Verbindung ablehnt (CONNECTED gefolgt von DISCONNECTED Event), weil z.B. der ESP nicht auf der Whitelist, oder in der Blacklist des APs steht, muss man den zweitbesten AP ausprobieren, usw. Daher werden die BSSIDs absteigend nach RSSI sortiert in eine Liste gepackt, die man abarbeitet, bis die Verbindung steht. Sollte keine Verbindung zustande kommen, fängt die Prozedur von vorne an (wie bisher auch: immer wieder neu versuchen). Mit dem Vorschlag hier kann man sich trotz Scan im AP Modus anmelden, ein laufender Scan wird dann abgebrochen. Wie bisher geht die Anmeldung allerdings nur bis zum ersten CONNECTED Event. Aber darauf kann ja ein DISCONNECTED folgen (s.o.) Besser wäre es, den AP Modus erst abzuschalten, wenn die Verbindung steht, d.h. beim 'GOT_IP' Event. Geht im Moment nicht, der DNSServer des AP Modus verhindert das. (Frage @lumapu braucht man mDns überhaupt? Ich hab' mal alle Vorkommen auskommentiert und sehe keinen Nachteil, alles läuft wie immer). Der Scanvorgang ist asynchron, analog zu dem (für die Web Oberfläche) schon vorhandenen, deshalb ist die RSSI Sortiermethode jetzt in einer eigenen Funktion (und getAvailNetworks minimal korrigiert). Ist der Scanvorgang fertig wird die Zeit bis zum Verbindungsversuch ggfs. auf 2 sec verkürzt. Hier muss man überlegen, ob ein anderer Wert sinnvoller ist. Sollte nicht zu sehr verkürzt werden, sonst hat man keine Chance mehr, in den AP Modus zu kommen. Dauert der Scanvorgang knapp mehr als 10 sec, würde man ohne Verkürzung weitere 10 sec warten. Die BSSID Liste ist einfach gehalten. BSSIDs werden immer als 6 uint_8t geliefert. Die schiebt man einfach in die Liste und liest sie entsprechen im 6er Block wieder aus (FIFO). Sind noch einige Debug Ausgaben für BSSID enthalten, nach belieben lassen, ändern oder löschen 😄. Und wie immer: hab' nur einen ESP32. Der Aufruf von WiFi.scanNetworks ist beim ESP8266 anders, bitte testen!

neu in ahoywifi.h

    private:
        void sortRSSI(int *sort, int n);
        void getBSSIDs(void);
        std::list<uint8_t> mBSSIDList;

Anpassungen in ahoywifi.cpp in setupStation die Zeile mStaConn = (WiFi.begin(...) != WL_CONNECTED) ? DISCONNECTED : CONNECTED; löschen, dafür die Zeile mBSSIDList.clear(); einfügen.

void ahoywifi::tickWifiLoop() {
    #if !defined(AP_ONLY)
    if(mStaConn != GOT_IP) {
        if (WiFi.softAPgetStationNum() > 0) { // do not reconnect if any AP connection exists
            if(mStaConn != IN_AP_MODE) {
                mStaConn = IN_AP_MODE;
                // first time switch to AP Mode
                if (mScanActive) {
                    WiFi.scanDelete();
                    mScanActive = false;
                }
                DBGPRINTLN(F("AP client connected"));
                welcome(mApIp.toString());
                WiFi.mode(WIFI_AP);
                mDns.start(53, "*", mApIp);
                mAppWifiCb(true);
            }
            mDns.processNextRequest();
            return;
        }
        else if(mStaConn == IN_AP_MODE) {
            mCnt = 0;
            mDns.stop();
            WiFi.mode(WIFI_AP_STA);
            mStaConn = DISCONNECTED;
        }
        mCnt++;

        if(!mScanActive && mBSSIDList.empty()) { // start scanning APs with the given SSID
            DBGPRINT(F("scanning APs with SSID "));
            DBGPRINTLN(String(mConfig->sys.stationSsid));
            mScanCnt = 0;
            mScanActive = true;
            #if defined(ESP8266)
            WiFi.scanNetworks(true, false, 0U, (uint8_t *)mConfig->sys.stationSsid);
            #else
            WiFi.scanNetworks(true, false, false, 300U, 0U, mConfig->sys.stationSsid);
            #endif
            return;
        }

        uint8_t timeout = 10; // seconds

        if (mStaConn == CONNECTED) // connected but no ip
            timeout = 20;

        DBGPRINT(F("reconnect in "));
        DBGPRINT(String(timeout-mCnt));
        DBGPRINTLN(F(" seconds"));
        if(mScanActive) {
            getBSSIDs();
            if(!mScanActive)        // scan completed
                if ((mCnt % timeout) < timeout - 2)
                    mCnt = timeout - 2;
        }
        if((mCnt % timeout) == 0) { // try to reconnect after x sec without connection
            if(mStaConn != CONNECTED)
                mStaConn = CONNECTING;
            if(mBSSIDList.size() > 0) { // get first BSSID in list
                DBGPRINT("try to connect to AP with BSSID:");
                uint8_t bssid[6];
                for (int j = 0; j < 6; j++) {
                    bssid[j] = mBSSIDList.front();
                    mBSSIDList.pop_front();
                    DBGPRINT(" "  + String(bssid[j], HEX));
                }
                DBGPRINTLN("");
                WiFi.disconnect();
                WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]);
            }
            mCnt = 0;
        }
    }
    #endif
}
//-----------------------------------------------------------------------------
void ahoywifi::sortRSSI(int *sort, int n) {
    for (int i = 0; i < n; i++)
        sort[i] = i;
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
            if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i]))
                std::swap(sort[i], sort[j]);
}

//-----------------------------------------------------------------------------
void ahoywifi::scanAvailNetworks(void) {
    if(!mScanActive) {
        mScanActive = true;
        if(WIFI_AP == WiFi.getMode())
          WiFi.mode(WIFI_AP_STA);
        WiFi.scanNetworks(true);
    }
}

//-----------------------------------------------------------------------------
void ahoywifi::getAvailNetworks(JsonObject obj) {
    JsonArray nets = obj.createNestedArray("networks");

    int n = WiFi.scanComplete();
    if (n < 0)
        return;
    if(n > 0) {
        int sort[n];
        sortRSSI(&sort[0], n);
        for (int i = 0; i < n; ++i) {
            nets[i]["ssid"]   = WiFi.SSID(sort[i]);
            nets[i]["rssi"]   = WiFi.RSSI(sort[i]);
        }
    }
    mScanActive = false;
    WiFi.scanDelete();
    if(mStaConn == IN_AP_MODE)
        WiFi.mode(WIFI_AP);
}

//-----------------------------------------------------------------------------
void ahoywifi::getBSSIDs() {
    int n = WiFi.scanComplete();
    if (n < 0) {
        mScanCnt++;
        if (mScanCnt < 20)
            return;
    }
    if(n > 0) {
        mBSSIDList.clear();
        int sort[n];
        sortRSSI(&sort[0], n);
        for (int i = 0; i < n; i++) {
            DBGPRINT("BSSID " + String(i) + ":");
            uint8_t *bssid = WiFi.BSSID(sort[i]);
            for (int j = 0; j < 6; j++){
                DBGPRINT(" " + String(bssid[j], HEX));
                mBSSIDList.push_back(bssid[j]);
            }
            DBGPRINTLN("");
        }
    }
    mScanActive = false;
    WiFi.scanDelete();
}

//-----------------------------------------------------------------------------
void ahoywifi::connectionEvent(WiFiStatus_t status) {
        ...
        case CONNECTED:
            if(mStaConn != CONNECTED) {
                mStaConn = CONNECTED;
                DBGPRINTLN(F("\n[WiFi] Connected"));
            }
            break;

        case GOT_IP:
            mStaConn = GOT_IP;
            if (mScanActive) {  // maybe another scan has started
                 WiFi.scanDelete();
                 mScanActive = false;
            }
            welcome(WiFi.localIP().toString() + F(" (Station)"));
            WiFi.mode(WIFI_STA);
            DBGPRINTLN(F("[WiFi] AP disabled"));
            mAppWifiCb(true);
            break;
        ...
}

Viel Spaß damit 😄

lumapu commented 1 year ago

Teil 1 ist umgesetzt, Teil 2 ist heavy! bist du dir sicher, dass diese Zeile so richtig ist?

void ahoywifi::tickWifiLoop() {
    ...
            if(WIFI_AP_STA == WiFi.getMode()) {
    ...

ich würde sagen sie muss weiterhin if((WIFI_AP_STA == WiFi.getMode()) && !mScanActive) { heißen

beegee3 commented 1 year ago

ja, die Zeile ist richtig, das ist so gewollt. In der nächsten Zeile wird auf mScanActive geprüft und der Scan ggfs. abgebrochen, um auf WIFI_AP Mode umzuschalten. Bei if((WIFI_AP_STA == WiFi.getMode()) && !mScanActive) würde man gar nicht umschalten, da mit dem ersten tickWifiLoop() sofort ein Scan gestartet wird (if(!mScanActive && mBSSIDList.empty()) ...). Wenn man sich während des Scans am AP anmeldet, d.h. WiFi.softAPgetStationNum() > 0 ist, wird mScanActive nicht mehr auf false gesetzt (selbst wenn der Scan fertig ist), da dies weiter unten durch getBSSIDs(); geschieht, wohin man aber wegen der AP Verbindung nicht mehr kommt. In Folge würden weder die 'AP welcome message' angezeigt, in den WIFI_AP Mode umgeschaltet, noch der 'App Callback' Aufruf durchgeführt. Die ersten beiden wären nicht dramatisch, aber ohne 'App Callback' sind wir wieder bei dem ganz oben im 1. Hinweis genannten Problem. Lange Rede, kurzer Sinn: all dies verhindert die Änderung der if Abfrage auf if(WIFI_AP_STA == WiFi.getMode()).

Das einzige, was noch passieren kann ist, dass man sich am AP anmeldet, während eine STA Verbindung aufgebaut wird. Dann ist nur die Frage, wer schneller den Modus umschaltet, AP oder STA. Der Schnellere wird den anderen mit der Umschaltung 'rauskicken'. Aber ist das ein Problem? Eher nicht. Wenn doch: vor dem ersten reconnect Versuch auf WIFI_STA umschalten, dann kann auch das nicht mehr passieren. Allerdings bleiben dem Nutzer dann nur 10 sec für eine AP Verbindung und das hatten wir doch schon einmal diskutiert (Vorsicht Katze😹)

stefan123t commented 1 year ago

Besser wäre es, den AP Modus erst abzuschalten, wenn die Verbindung steht, d.h. beim 'GOT_IP' Event. Geht im Moment nicht, der DNSServer des AP Modus verhindert das. (Frage @lumapu braucht man mDns überhaupt? Ich hab' mal alle Vorkommen auskommentiert und sehe keinen Nachteil, alles läuft wie immer).

@beegee3 ich dachte mDns wird u.a. im AP Modus benötigt um die Captive Portal Funktion des ESP bereit zu stellen und im STA Modus brauchen wir es m.W. damit sich der ESP als ahoy-dtu beim Router meldet und unter diesem Namen registriert wird.

lumapu commented 1 year ago

@stefan123t den ersten Punkt würde ich auch so sehen, aber ein Test von @beegee3 hatte gezeigt, dass dies uU. garnicht nötig ist. Für den richtigen Namen in der Fritzbox ist DNS hier nicht nötig

beegee3 commented 1 year ago

@stefan123t @lumapu die Namensfestlegung erfolgt über WiFi.hostname(...) in ahoywifi::setupStation. Captive Portal Funktion: mein Fehler🤕,dachte dabei bisher nur an eine Weiterleitung im Sinne eines Repeater. Aber man braucht natürlich mDns.processNextRequest(), wenn man sich mit mehr als einem Gerät am AP anmeldet, um Anfragen und Antworten zuzuordnen. Diese Funktionalität wird nur im AP Modus benötigt und auch nur dann, wenn mind. 1 Gerät angemeldet ist. Ob das der Fall ist, wird bereits jetzt in tickWifiLoop() festgestellt. Es genügt also, DNS Start und Stopp daran zu koppeln und kann dann auch den AP Modus erst beim 'GOT_IP' Event abschalten. D.h. mDns.start(...) aus setupAp() raus, mDns.stop() aus connectionEvent(...) raus und beides in tickWifiLoop() rein. Hab' den Code im 1. Beitrag oben entsprechend angepasst. (setupAp() ist oben nicht angegeben; also mDns.start(...) löschen nicht vergessen 😃)

Frage: braucht man mDns.processNextRequest() bei AP_ONLY eigentlich nicht?

stefan123t commented 1 year ago

Und im STA Modus braucht man mDns nicht ? Ich kann doch dann auch von zwei Geräten zugreifen bzw auch die Namensauflösung für MQTT Broker, NTP Server, etc. oder macht das die ESPWifi Bibliothek ohne mDns ?

beegee3 commented 1 year ago

im STA Modus kommuniziert der ESP nur mit dem einen AP zu dem er verbunden ist (i.a. ein Router wie z.B. die Fritzbox), andere Geräte kennt er nicht! Dieser AP (nennen wir ihn Router) macht die ganze Kommunikationsarbeit, d.h. die Namensauflösung. Verbindungen mit anderen IP Adressen laufen i.d.R. auch über den Router und werden von diesem durchgereicht. Über die IP Adressen, die der ESP vom Router erhält, unterscheidet er die verschiedenen Geräte und kommuniziert so auch mit MQTT Broker und NTP Server.

beegee3 commented 1 year ago

Hatte heute einen endlosen Wifi Scan, weil wohl kein 'Scan Complete' gemeldet wurde. Daher eine kleine Anpassung im Code oben. Ein Counter mScanCnt (= 0 bei Scan Start in tickWifiLoop()) wird in getBSSIDs() hochgezählt. Nach 20 erfolglosen 'Scan Complete' Abfragen (= 20 sec) wird der Scan abgebrochen. tickWifiLoop() starten danach einen neuen Scan. Die 20 Sekunden sollten ausreichen, damit nicht jeder Scan abgebrochen wird. Evtl. aber hochsetzen, um auf der sicheren Seite zu sein.

knickohr commented 1 year ago

Ich wurde gerade unfreiwillig Tester dieser neuen Funktion. Weibilein hat den Repeater gezogen weil da unbedingt der Staubsauger jetzt rein muß 🤪

Funktioniert, er geh sofort zum nächstbesten AP den er findet 😎 aaaber, er geht nicht mehr zurück wenn ein noch besserer wieder da ist. Offenbar bleibt er solange hängen bis eben dieser vorher bessere auch wieder ausfällt.

Kann man das noch optimieren ?

knickohr commented 1 year ago

Stop ! Kommando zurück, er macht es. Dauert halt nur ein paar Minuten 🤭

Ich habe nüx gesagt 🙉🙈🙊

beegee3 commented 1 year ago

@knickohr 🤔eigentlich bleibt die Verbindung, ein permanenter Scan um einen besseren AP zu finden (wie bei den Shellies) ist nicht vorgesehen (wo soll der Vorteil sein?). Vielleicht ist bei dir die Verbindung zum zweitbesten abgebrochen, nachdem der beste wieder vorhanden war (das 'Staubsauger Phänomen' 😁).

knickohr commented 1 year ago

Naja, -88dBm ist nicht gerade stark, er wird wohl wieder gewechselt haben 😉

Oder das Mesh der Fritz!Box regelt das. Keine Ahnung.

lumapu commented 1 year ago

@knickohr der Code ist doch noch garnicht in der dev drin 😳😉.

@beegee3 ich bin auch noch am probieren mit deinem Code, da der Scan in AP Modus eher schlecht als Recht funktioniert. Ich denke ich bin schon auf einen guten Weg, gleichzeitig drängt sich mir das Gefühl auf, das wir noch ein paar Iterationen brauchen bis es wieder perfekt ist.

beegee3 commented 1 year ago

@lumapu Scan in AP Modus??? Im WIFI_AP gibt's doch keinen Scan! Hast du mDns.start(...) in setupAp() und mDns.stop() in connectionEvent(...) gelöscht? Beides ist doch jetzt in tickWifiLoop(). Und bitte auch die Position von mDns.processNextRequest(); beachten (nach if(WIFI_AP_STA == WiFi.getMode()) {...}, s.o.).

knickohr commented 1 year ago

Bitte ?!

Dann macht das Fritz! Mesh da definitiv was 😲

Nun ja gut, waren Ausfälle, also mußte er ja wohin connecten.

lumapu commented 1 year ago

@beegee3 ja ich meinte natürlich den kombinierten Modus, deinen Code habe ich zuerst komplett übernommen und dann das testen angefangen 😊. Wenn ich mich zum AP AHOY-DTU verbinde und dann auf Scan drücke bekomme ich fast immer Error: Deserialization oder No networks found. Dann habe ich angefangen mir auf die Konsole Ausgaben zu machen, wenn gestartet wird zu scannen und wenn die Netzwerke abgefragt werden. Daher fällt auf, dass nur jedes zweite Mal der Scan gestartet wird. Ich habe schon einen Lösungsansatz, bin aber nur testen noch nicht fertig.

beegee3 commented 1 year ago

Error: Deserialization kommt doch von JSON. Wohl zu viele Netze, oder zu lange SSID Namen in deiner Umgebung? 😀 Habs' jetzt 20 mal ausprobiert, jedesmal wurde der Scan gestartet und jedesmal ohne Probleme die NWs angezeigt! 🤔

beegee3 commented 1 year ago

hab oben die Wartezeitverkürzung nochmal angepasst, war nicht wie gewünscht.

lumapu commented 1 year ago

@beegee3 mein Problem ist die Zeile mAppWifiCb(true); in tickWifiLoop(). Wenn ich es zu mAppWifiCb(false); ändere, klappt das Scannen im WIFI_AP_STA Modus wieder.

beegee3 commented 1 year ago

🤔 merkwürdig. Ich hatte beim Testen zunächst auch mAppWifiCb(false);, habe dann aber bemerkt, dass dann ja nur loopWifi läuft und keine Inverter Daten verarbeitet werden. Also total eingeschränkt. Wenn es nur dazu dienen soll, Settings zu verändern (insbes. Network), reicht das natürlich. Mit mAppWifiCb(true); wird ohne Browser Zeitsync natürlich auch nichts angezeigt. Das hab ich daher immer als erstes gemacht, bevor ich einen Scan aufgerufen habe. 💡 Natürlich, daran liegt es: ohne Zeitangabe läuft ständig mWifi.getNtpTime();. Das lässt sich ändern mit:

void app::tickNtpUpdate(void) {
    uint32_t nxtTrig = 5;  // default: check again in 5 sec
    bool isOK;
    if(WIFI_AP == WiFi.getMode())
        isOK = false;
    else
        isOK = mWifi.getNtpTime();
    if (isOK || mTimestamp != 0) {
      ...
lumapu commented 1 year ago

💡 Natürlich, daran liegt es: ohne Zeitangabe läuft ständig mWifi.getNtpTime();. Das lässt sich ändern mit:

aber der fliegt doch sofort raus oder? Weiß nicht ob das was verbessert. 🤔


bool ahoywifi::getNtpTime(void) {
    if(GOT_IP != mStaConn)
        return false;

    ...
``
beegee3 commented 1 year ago

@lumapu

aber der fliegt doch sofort raus oder?

stimmt, du hast Recht. Mein Fehler (war spät am Abend 🌕). Suchte nach Prozessen, die auf's Wifi zugreifen. Es ist nicht Ntp, sondern Mqtt (was ich testweise abgeklemmt hatte). Wird das im WIFI_AP Mode unterdrückt, dann funktioniert auch mAppWifiCb(true);. Also in app::onWifi das mMqttEnabled anpassen:

        ...
        if(WIFI_AP == WiFi.getMode()) {
            mMqttEnabled = false;
            everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL");
        }
        ...

Mit der v0.5.78 verstehe ich jetzt auch deine Scan Probleme. Da war wieder 'die Katze, die sich in den Schwanz beißt' 🐈:

  1. am ESP AP angemeldet -> tickWifiLoop: WiFi.softAPgetStationNum() > 0, also WIFI_AP aktiviert
  2. scanAvailNetworks: WIFI_AP_STA aktiviert, Scan gestartet
  3. tickWifiLoop: WiFi.softAPgetStationNum() > 0, also Scan abgebrochen, WIFI_AP wieder aktiviert
  4. getAvailNetworks liefert Error: Deserialization oder No networks found

keine Ahnung, warum das bei mir klappte (einziger Unterschied: ich hatte mAppWifiCb(true)). Damit die Katze heil bleibt, darf tickWifiLoop nur einmal den WIFI_AP Mode aktivieren. Ich finde deine Lösung in v0.5.78 etwas umständlich. Außerdem wird der BSSID Scan erst nach 20 sek ausgeführt. Wahrscheinlich hast du das geändert, weil es direkt nicht funktionierte, was aber nur daran liegt, dass immer noch in setupAp() mDns.start(...) und in connectionEvent(...) mDns.stop() steht. Wie bereits oben erwähnt, müssen diese Zeilen dort gelöscht werden! DNS wird nur noch in tickWifiLoop gestartet bzw. gestoppt! Zur Katze: in mStaConn ist doch der für uns relevante, aktuelle Wifi Zustand gespeichert. Mit einem zusätzlichen Zustand IN_AP_MODE kann tickWifiLoop vernünftig reagieren, der BSSID Scan sofort gestartet werden und man braucht kein mLastApClients. Habe oben im 1. Beitrag den Code entsprechend angepasst (tickWifiLoop, getAvailNetworks). Zusätzlich ist in scanAvailNetworks die Zeile if(-2 == WiFi.scanComplete()) { durch if(!mScanActive) { ersetzt, so dass kein zweiter Scan gestartet werden kann, wenn der erste noch läuft (wenn z.B. zwei Clients zur gleichen Zeit einen Scan aufrufen). Und in ahoywifi.hden WiFiStatus erweitert zu

        typedef enum WiFiStatus {
            DISCONNECTED = 0,
            CONNECTING,
            CONNECTED,
            IN_AP_MODE,
            GOT_IP
        } WiFiStatus_t;
lumapu commented 1 year ago

@beegee3 für den ESP32 können wir es uns scheinbar einfacher machen mit folgenden zwei Zeilen:

WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
beegee3 commented 1 year ago

@lumapu hatte ich auch gesehen, als ich nach einer Lösung gesucht habe. Für ESP32 die einfachste Methode. Damit es auch für den ESP8266 funktioniert, ist es halt (etwas) komplizierter geworden. Im Prinzip werden genau diese beiden Zeilen 'nachgebaut'. Hast du eigentlich meinen letzten Vorschlag (klare Trennung zwischen Scan und Connect mit Scan Animation) mal ausprobiert? Sollte deine in den logs beschriebenen Probleme beseitigen und auch den Verbindungsaufbau verkürzen (bei mir sind es in der Regel 13 Sekunden, wovon 10 Sekunden ja Minimum Vorgabe sind).

lumapu commented 1 year ago

wir disktutieren in #652 weiter