Closed beegee3 closed 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
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😹)
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.
@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
@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?
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 ?
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.
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.
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 ?
Stop ! Kommando zurück, er macht es. Dauert halt nur ein paar Minuten 🤭
Ich habe nüx gesagt 🙉🙈🙊
@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' 😁).
Naja, -88dBm ist nicht gerade stark, er wird wohl wieder gewechselt haben 😉
Oder das Mesh der Fritz!Box regelt das. Keine Ahnung.
@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.
@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.).
Bitte ?!
Dann macht das Fritz! Mesh da definitiv was 😲
Nun ja gut, waren Ausfälle, also mußte er ja wohin connecten.
@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.
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! 🤔
hab oben die Wartezeitverkürzung nochmal angepasst, war nicht wie gewünscht.
@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.
🤔 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) {
...
💡 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;
...
``
@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' 🐈:
tickWifiLoop
: WiFi.softAPgetStationNum() > 0
, also WIFI_AP
aktiviertscanAvailNetworks
: WIFI_AP_STA
aktiviert, Scan gestartettickWifiLoop
: WiFi.softAPgetStationNum() > 0
, also Scan abgebrochen, WIFI_AP
wieder aktiviertgetAvailNetworks
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.h
den WiFiStatus
erweitert zu
typedef enum WiFiStatus {
DISCONNECTED = 0,
CONNECTING,
CONNECTED,
IN_AP_MODE,
GOT_IP
} WiFiStatus_t;
@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);
@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).
wir disktutieren in #652 weiter
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 aufapp::loopStandard
umzuschalten, ist inahoywifi::tickWifiLoop
nachWiFi.mode(WIFI_AP);
nochmAppWifiCb(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 inapp::onWifi
: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 vonDISCONNECTED
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 erstenCONNECTED
Event. Aber darauf kann ja einDISCONNECTED
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 manmDns
ü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 (undgetAvailNetworks
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 6uint_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 vonWiFi.scanNetworks
ist beim ESP8266 anders, bitte testen!neu in ahoywifi.h
Anpassungen in ahoywifi.cpp in
setupStation
die ZeilemStaConn = (WiFi.begin(...) != WL_CONNECTED) ? DISCONNECTED : CONNECTED;
löschen, dafür die ZeilemBSSIDList.clear();
einfügen.Viel Spaß damit 😄