theelims / ESP32-sveltekit

A simple and extensible framework for ESP32 based IoT projects with a feature-rich, beautiful, and responsive front-end build with Sveltekit, Tailwind CSS and DaisyUI. This is a project template to get you started in no time with a fully integrated build chain.
https://theelims.github.io/ESP32-sveltekit/
Other
90 stars 15 forks source link

Wifi state - ap mode or sta mode #30

Closed besanur closed 2 months ago

besanur commented 3 months ago

Hello, I've been stuck on a topic for some time now, so I thought I might find some help here. I'm using this project, and I've connected a display to my ESP32-S2 where I want to display certain things, for example, weather data.

It should work as follows:

  1. When the device is turned on, the AP access data should be displayed on the display.
  2. Once the device is connected to a home network (i.e., STA Mode), the access data on the display should be cleared and something else should be displayed.

My problem now is that I'm using the two classes WiFiSettingsService and APsettingsService to solve this. However, I haven't managed to do this because the device first goes into STA mode when starting and then sometimes turns the AP mode on or off. When the device is in STA mode, the AP access data continues to be displayed. Somehow, I'm not getting anywhere. Do you have any idea how I should proceed?

runeharlyk commented 3 months ago

Are you currently pooling the network status or using WiFi event callbacks to know when to update the display?

Your display service can either periodically checks if APSettingsService::getAPNetworkStatus() is not APNetworkStatus::INACTIVE or register callback function for a WiFi event like: WiFi.onEvent(SERVICE_CB, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED).

Can you share some of the current code?

theelims commented 3 months ago

Depending on you configured the AP modes it will always start with the AP mode. It will take 3-5 seconds until STA mode is established and connected. In your case I would simply work around the issue and show a splash screen for the first few seconds. If STA mode doesn't come up within that time display the AP settings. Else directly start with the STA.

As suggested you can also use the WiFi events. ESP32-Sveltekit uses WiFi.onEvent(callback, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); a couple of times to achieve the exact same thing. NTPSettingsService and MqttSettingsService both use this to determine when to connect to their respective servers.

besanur commented 3 months ago

Super thank you. I'll try that

besanur commented 2 months ago

Are you currently pooling the network status or using WiFi event callbacks to know when to update the display?

Your display service can either periodically checks if APSettingsService::getAPNetworkStatus() is not APNetworkStatus::INACTIVE or register callback function for a WiFi event like: WiFi.onEvent(SERVICE_CB, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED).

Can you share some of the current code?

sorry, I didn't see your answer at all ^^ thanks for that.

This is my current code. It works basically, but sometimes the events overtake each other and it switches back and forth. Small optimizations are needed.

#include <WifiConnectionService.h>

WifiConnectionService::WifiConnectionService(DisplayService *displayService,
                                             StatefulService<APSettings> *apSettings,
                                             StatefulService<WiFiSettings> *wifiSettings)
    : _displayService(displayService),
      _apSettings(apSettings),
      _wifiSettings(wifiSettings) {}

void WifiConnectionService::begin(){
    WiFi.onEvent(std::bind(&WifiConnectionService::WiFiEvent, this, std::placeholders::_1));
    _displayService->horizontalCenter("Connecting to WiFi..", 1, u8g2_font_timB18_tr, WHITE, 140);
}

void WifiConnectionService::WiFiEvent(WiFiEvent_t event){
  unsigned long currentMillis = millis();
  if (!_lastRequest || (unsigned long)(currentMillis - _lastRequest) >= (10 * 1000) && WiFi.getMode() == WIFI_AP)
  {
    switch (event) {
      case ARDUINO_EVENT_WIFI_STA_GOT_IP:
        onSTAMode();
        break;
      case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
      case ARDUINO_EVENT_WIFI_AP_START:
        onAPMode();
        break;
      default: break;
    }
  }
}

void WifiConnectionService::loop(){
  unsigned long currentMillis = millis();
  bool currentWifiStatus = WiFi.status() == WL_CONNECTED;
  if (!_lastRequest || (unsigned long)(currentMillis - _lastRequest) >= (30 * 1000) && currentWifiStatus != _lastWifiStatus){
    _lastRequest = currentMillis;

    if(currentWifiStatus){
      onSTAMode();
    } else if(isApActive()){
      onAPMode();
    }    
    _lastWifiStatus = currentWifiStatus;
  }
}

void WifiConnectionService::onSTAMode(){
  Serial.println("Wifi connected to STA");
  _displayService->clearScreen();

}

void WifiConnectionService::onAPMode(){
  _displayService->clearScreen();
  Serial.println("AP mode active");
  _apSettings->read([&](APSettings &apSettings){
    _displayService->horizontalCenter("Connect to WIFI", 1, u8g2_font_timB18_tr, WHITE, 40);

    _displayService->horizontalCenter("WiFi AP", 1, u8g2_font_timB10_tr, ORANGE, 80);
    _displayService->horizontalCenter(apSettings.ssid, 1, u8g2_font_timB10_tr, WHITE, 100);

    _displayService->horizontalCenter("Password", 1, u8g2_font_timB10_tr, ORANGE, 140);
    _displayService->horizontalCenter(apSettings.password, 1, u8g2_font_timB10_tr, WHITE, 160);

    _displayService->horizontalCenter("IP", 1, u8g2_font_timB10_tr, ORANGE, 200);
    _displayService->horizontalCenter(apSettings.localIP.toString(), 1, u8g2_font_timB10_tr, WHITE, 220);
  });
}

boolean WifiConnectionService::isApActive()
{
  WiFiMode_t currentWiFiMode = WiFi.getMode();
  bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA;

  return apActive;
}