Open Jagakatt opened 1 year ago
Can you layout an overview of how you want it to flow? We might need to add additional callouts, there are some open issues etc about similar
Thanks for asking! Do almost get a little Christmas feeling when I can which for something! :-) It would be nice for normal non nerdy people to complete the "ConfigPortal" which I have realized watching normal people in action can be a bit confusing. So be able get some trigger to react upon when:
To be able to get some trigger of the above listed situation would at least enable me to create some nice assistance for the enduser. And I assume the NonLocking mode is the way be able to run code to toggle between messages on small displays when in portal-mode. Thanks!
I assume you know about the existingones already ?
//callbacks
// called after AP mode and config portal has started
// setAPCallback( std::function<void(WiFiManager*)> func );
//
// called after webserver has started
// setWebServerCallback( std::function<void()> func );
//
// called when settings reset have been triggered
// setConfigResetCallback( std::function<void()> func );
//
// called when wifi settings have been changed and connection was successful ( or setBreakAfterConfig(true) )
// setSaveConfigCallback( std::function<void()> func );
//
// called when saving either params-in-wifi or params page
// setSaveParamsCallback( std::function<void()> func );
//
// called when saving params-in-wifi or params before anything else happens (eg wifi)
// setPreSaveConfigCallback( std::function<void()> func );
//
// called just before doing OTA update
// setPreOtaUpdateCallback( std::function<void()> func );
heres a crappy demo, it works, but do not use this code permanantly, just an example. I just added some callbacks into your example. in reality you should be setting states in these callbacks and NOT actually doing stuff.
Then do stuff based on those states in loop etc, for example DO NOT actually delay or print inside callbacks but keep them fast as possible. But this is quick and dirty for concept. I will work on a proper example to add to the lib ro lcd and oled maybe
// Liquidcrystal demo
// WiFiManager in non blocking mode to toggle between messages on display. (Not made by a programmer.....)
// Original sketch: https://github.com/tzapu/WiFiManager/blob/master/examples/NonBlocking/AutoConnectNonBlocking/AutoConnectNonBlocking.ino
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows connected to SCL --> D1, SDA -> D2
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
WiFiManager wm;
void setup() {
WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP
// put your setup code here, to run oQnce:
Serial.begin(115200);
Serial.setDebugOutput(false);
Wire.setClock(400000L); // set i2c speed 400khz
Wire.begin();
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connecting to wifi .....");
//reset settings - wipe credentials for testing
wm.resetSettings();
wm.setAPCallback(configModeCallback);
// wm.setWebServerCallback(bindServerCallback);
wm.setSaveConfigCallback(saveWifiCallback);
// wm.setSaveParamsCallback(saveParamCallback);
// wm.setPreOtaUpdateCallback(handlePreOtaUpdateCallback);
wm.setConfigPortalBlocking(false);
std::vector<const char *> menu = { "wifi", "restart", "exit" }; // Added by me...
wm.setMenu(menu);
wm.setConfigPortalTimeout(60);
//automatically connect using saved credentials if they exist
//If connection fails it starts an access point with the specified name
if (wm.autoConnect("MyPortal", "password")) {
Serial.println("connected...yeey)");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connected!!!");
// } else {
// Serial.println("Configportal running"); // Not possible to see when
// runningConfigPortal = true;
}
}
void saveWifiCallback(){
Serial.println("[CALLBACK] saveCallback fired");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Saving new wifi....");
delay(2000);
}
//gets called when WiFiManager enters configuration mode
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println("[CALLBACK] configModeCallback fired");
// myWiFiManager->setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
// Serial.println(WiFi.softAPIP());
//if you used auto generated SSID, print it
// Serial.println(myWiFiManager->getConfigPortalSSID());
//
// esp_wifi_set_bandwidth(WIFI_IF_AP, WIFI_BW_HT20);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("NO WiFi, Connect to AP: " + wm.getConfigPortalSSID());
delay(1000);
}
void checkPortalState(){
bool cp = wm.getConfigPortalActive();
bool wp = wm.getWebPortalActive();
lcd.clear();
lcd.setCursor(0, 0);
if(cp){
lcd.print("Portal Running...");
delay(1000);
} else {
lcd.print("Portal Closed!");
delay(1000);
}
}
unsigned int currentMillis;
unsigned int startMillis;
unsigned int WiFiErrorCount;
bool portalMode;
bool startingUp = true;
void loop() {
wm.process();
// put your main code here, to run repeatedly:
currentMillis = millis();
if (currentMillis - startMillis > 2000) { //test whether the period has elapsed
String checkMode;
checkMode = WiFi.softAPIP().toString(); // See if this returns 192.168.4.1 = Portal Mode. Did not manage to find any other way to get notice
Serial.println(checkMode); // of when exiting from "PortalMod".
if (checkMode == "192.168.4.1") {
Serial.println("###################################### IN PORTAL MODE ################### ");
portalMode = true;
startingUp = true;
} else {
portalMode = false;
}
Serial.print("Every second - WiFi.status is : ");
Serial.println(WiFi.status());
if (WiFi.status() == WL_CONNECTED) { //
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connected!!!");
WiFiErrorCount = 0;
startingUp = false;
} else if ((WiFi.status() != WL_CONNECTED) && (portalMode == false)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("NOT Connected!!!");
lcd.setCursor(0, 1);
lcd.print("Restarting.");
lcd.print(WiFiErrorCount);
WiFiErrorCount++;
if ((WiFiErrorCount > 100) && (startingUp == false)) { // Restart device after about 200 sec if no WiFi.
ESP.restart();
}
}
startMillis = currentMillis;
}
checkPortalState();
if ((WiFi.status() != WL_CONNECTED) && (portalMode == true)) { // Show configuration messages on display if no WiFi and in PortalMode.
portalDisplayMessages();
}
if (WiFi.status() == WL_CONNECTED) {
// futureCrappyCode(); // Code dependent on an active WiFi connection.
}
delay(1000);
}
void portalDisplayMessages() {
int currentMillis;
static unsigned int startMillis;
static unsigned int messageCount = 0;
currentMillis = millis();
if (currentMillis - startMillis > 10000) { //test whether the period has elapsed
Serial.println("Running portal, 10 seconds message switch");
switch (messageCount) {
case 0:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("AccessPoint:");
lcd.setCursor(0, 1);
lcd.print("MyPortal");
messageCount++;
break;
case 1:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Password:");
lcd.setCursor(0, 1);
lcd.print("gggggggg");
messageCount = 0;
}
startMillis = currentMillis;
}
}
I assume you know about the existingones already ?
//callbacks // called after AP mode and config portal has started // setAPCallback( std::function<void(WiFiManager*)> func ); // // called after webserver has started // setWebServerCallback( std::function<void()> func ); // // called when settings reset have been triggered // setConfigResetCallback( std::function<void()> func ); // // called when wifi settings have been changed and connection was successful ( or setBreakAfterConfig(true) ) // setSaveConfigCallback( std::function<void()> func ); // // called when saving either params-in-wifi or params page // setSaveParamsCallback( std::function<void()> func ); // // called when saving params-in-wifi or params before anything else happens (eg wifi) // setPreSaveConfigCallback( std::function<void()> func ); // // called just before doing OTA update // setPreOtaUpdateCallback( std::function<void()> func );
Sorry, I did not know of the existing ones. And even less how to put them in action. It's just a lot of magic lines of code that unfortunately makes no sense to me. Played around earlier with what's found under "Callbacks" on the WiFiManager main page here, but without success. I have only programmed for a few months so I am still at the level where I get totally chocked every time the compilation goes through without a few pages of red text...
But I definitely think I will manage to progress further thanks to the pieces of code you added to my sketch!! I will upload a cleaner version here in a few days. THANK YOU SO MUCH!!!
This was obviously written on a monochrome monitor...
// A sketchy sketch to show messages on a LCD1602 when WiFiManager is in "non blocking mode"
// Messages about network status and WiFimanager configuration portal.
// And nope, I do not consider myself as a skilled programmer, but after scanning the Internet I realized I am not the only one not managing to execute code when the portal was active.
// So hopefully it can help someone.
// At least what's found below fulfilled my requirements, even though there are probably a zillion ways to do it in a better way, so feel free to modify! :-)
// Fredrik
// To be added somehow: A message when wrong network credentials were entered.
// Looks like "saveWifiCallback" only is executed when proper network credentials were entered.
// But no big deal. :-)
// Setup LCD1602 with I2C-interface
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows connected to SCL --> D1, SDA -> D2
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
WiFiManager wm;
bool starting;
bool newWIFIsuccess = false;
void setup() {
WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP
// put your setup code here, to run oQnce:
Serial.begin(115200);
Serial.setDebugOutput(true); //
lcd.init(); // initialize the lcd
lcd.backlight();
starting = true;
displayWiFimanagerMessages(); // Just to show the initial message.
//reset settings - wipe credentials for testing
//wm.resetSettings();
wm.setAPCallback(configModeCallback);
// wm.setWebServerCallback(bindServerCallback);
wm.setSaveConfigCallback(saveWifiCallback);
// wm.setSaveParamsCallback(saveParamCallback);
// wm.setPreOtaUpdateCallback(handlePreOtaUpdateCallback);
wm.setConfigPortalBlocking(false);
std::vector<const char *> menu = { "wifi", "restart", "exit" }; // Limit the portal buttuns to these three.
wm.setMenu(menu);
wm.setConfigPortalTimeout(120);
//automatically connect using saved credentials if they exist
//If connection fails it starts an access point with the specified name
if (wm.autoConnect("MyPortal", "MyPassword")) {
Serial.println("connected...yeey)");
// lcd.clear();
// lcd.setCursor(0, 0);
// lcd.print("Connected!!!");
} else {
}
}
void loop() {
wm.process(); // WiFimanager to be executed frequently.
displayWiFimanagerMessages();
}
void displayWiFimanagerMessages() {
static unsigned int messageCount = 0;
static unsigned long previousMillis = 0; // To run directly (== 0) when called from "Setup"
if (millis() - previousMillis > 3000 || previousMillis == 0) { // Toggle between messages every 3s.
previousMillis = millis();
//Serial.println(wm.getWiFiPass()); // <-- Will get you the stored Passwd
//Serial.println(wm.getWiFiSSID()); // <-- Will get you the stored SSID
if (starting) { // Displayed when starting
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connecting to...");
lcd.setCursor(0, 1);
lcd.print(wm.getWiFiSSID());
starting = false;
return;
}
if (WiFi.status() == WL_CONNECTED && !wm.getConfigPortalActive()) { // Displayed when successfully connedted to network.
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connected to:");
lcd.setCursor(0, 1);
lcd.print(wm.getWiFiSSID());
Serial.println("Connected to : ");
Serial.println(wm.getWiFiSSID());
} else {
// lcd.clear();
// lcd.setCursor(0, 0);
// lcd.print("NOT Connected!!!");
// Serial.println("NOT Connected!!!");
}
if (WiFi.status() != WL_CONNECTED) { // Displayed after loosing connection, and after Config portal timeout.
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("No WiFi :-\(\ ");
lcd.setCursor(0, 1);
lcd.print("Not good...");
}
if (newWIFIsuccess) { // Displayed after proper network credentials have been enterd in portal.
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Config");
lcd.setCursor(0, 1);
lcd.print("Success!!");
newWIFIsuccess = false;
}
if (wm.getConfigPortalActive()) { // Toggle between help messages on display as long as the Config Portal is active.
switch (messageCount) {
case 0:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("No Internet!");
lcd.setCursor(0, 1);
lcd.print("Starting config.");
messageCount++;
break;
case 1:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connect to Wifi:");
lcd.setCursor(0, 1);
lcd.print(wm.getConfigPortalSSID());
messageCount++;
break;
case 2:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Password:");
lcd.setCursor(0, 1);
lcd.print("MyPassword");
messageCount++;
break;
case 3:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("--> Conf. WiFi:");
lcd.setCursor(0, 1);
lcd.print("Select Network");
messageCount++;
break;
case 4:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("--> Save");
lcd.setCursor(0, 1);
messageCount = 0;
}
}
if (wm.getWebPortalActive()) {
//Serial.println("Web Portal is Active");
}
}
}
void configModeCallback(WiFiManager *myWiFiManager) { //gets called when WiFiManager enters configuration mode
Serial.println("[CALLBACK] configModeCallback fired");
// myWiFiManager->setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
// Serial.println(WiFi.softAPIP());
//if you used auto generated SSID, print it
// Serial.println(myWiFiManager->getConfigPortalSSID());
//
// esp_wifi_set_bandwidth(WIFI_IF_AP, WIFI_BW_HT20);
// lcd.clear();
// lcd.setCursor(0, 0);
// lcd.print("NO WiFi, Connect to AP: " + wm.getConfigPortalSSID());
// delay(1000);
}
void saveWifiCallback() { // Executed when saving new network credentials.
Serial.println("[CALLBACK] saveCallback fired. Saving new network credentials."); /// Only seam to be execuded when saving valid network credentials.
newWIFIsuccess = true; // To trigger message when proper network credentials have been entered.
// lcd.clear();
// lcd.setCursor(0, 0);
// lcd.print("Saving new wifi....");
// delay(2000);
}
void checkPortalState() {
// bool cp = wm.getConfigPortalActive();
// bool wp = wm.getWebPortalActive();
// lcd.clear();
// lcd.setCursor(0, 0);
// if (cp) {
// lcd.print("Portal Running...");
// delay(1000);
// } else {
// lcd.print("Portal Closed!");
// delay(1000);
// }
}
Is this a working update?
Yes, it does work. But keep in mind that I'm new to coding.
maybe it helps, here s a sketch i ve used long ago that uses a tiny oled and displays connection prompt/statuses, ota statuses and so on. it illustrates callback usage. credits to all the people that made the original
/**The MIT License (MIT)
Copyright (c) 2016 by Daniel Eichhorn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
See more at http://blog.squix.ch
*/
/* Customizations by Neptune (NeptuneEng on Twitter, Neptune2 on Github)
*
* Added Wifi Splash screen and credit to Squix78
* Modified progress bar to a thicker and symmetrical shape
* Replaced TimeClient with built-in lwip sntp client (no need for external ntp client library)
* Added Daylight Saving Time Auto adjuster with DST rules using simpleDSTadjust library
* https://github.com/neptune2/simpleDSTadjust
* Added Setting examples for Boston, Zurich and Sydney
* Selectable NTP servers for each locale
* DST rules and timezone settings customizable for each locale
* See https://www.timeanddate.com/time/change/ for DST rules
* Added AM/PM or 24-hour option for each locale
* Changed to 7-segment Clock font from http://www.keshikan.net/fonts-e.html
* Added Forecast screen for days 4-6 (requires 1.1.3 or later version of esp8266_Weather_Station library)
* Added support for DHT22, DHT21 and DHT11 Indoor Temperature and Humidity Sensors
* Fixed bug preventing display.flipScreenVertically() from working
* Slight adjustment to overlay
*/
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include "settings.h"
#include <JsonListener.h>
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
#include <time.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <PubSubClient.h> //https://github.com/Imroy/pubsubclient
#include "WundergroundClient.h"
#include "WeatherStationFonts.h"
#include "WeatherStationImages.h"
#include "DSEG7Classic-BoldFont.h"
#include "ThingspeakClient.h"
Adafruit_BMP280 bme;
WiFiClient wclient;
PubSubClient mqttClient(wclient);
int lastMQTTConnectionAttempt = 0;
// Initialize Wunderground client with METRIC setting
WundergroundClient wunderground(IS_METRIC);
// Initialize the temperature/ humidity sensor
float humidity = 0.0;
float temperature = 0.0;
ThingspeakClient thingspeak;
// flag changed in the ticker function every 10 minutes
bool readyForWeatherUpdate = false;
// flag changed in the ticker function every 1 minute
bool readyForIndoorUpdate = false;
String lastUpdate = "--";
Ticker ticker;
//declaring prototypes
void configModeCallback (WiFiManager *myWiFiManager);
void drawProgress(OLEDDisplay *display, int percentage, String label);
void drawOtaProgress(unsigned int, unsigned int);
void updateData(OLEDDisplay *display);
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecast2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawIndoor(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawThingspeak(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex);
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
void setReadyForWeatherUpdate();
int8_t getWifiQuality();
// Add frames
// this array keeps function pointers to all frames
// frames are the single views that slide from right to left
FrameCallback frames[] = { drawDateTime, drawIndoor, drawCurrentWeather, drawForecast, drawForecast2 };
int numberOfFrames = 5;
//FrameCallback frames[] = { drawDateTime, drawIndoor, drawCurrentWeather };
//int numberOfFrames = 3;
OverlayCallback overlays[] = { drawHeaderOverlay };
int numberOfOverlays = 1;
void setup() {
Serial.begin(115200);
//power display - wemos d1 mini quick plug
pinMode(5, OUTPUT);
digitalWrite(5, HIGH);
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
// initialize display
display.init();
display.clear();
display.display();
display.flipScreenVertically(); // Comment out to flip display 180deg
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setContrast(255);
// Credit where credit is due
display.drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
display.display();
//BMP280
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BMP280 sensor, check wiring!");
}
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
// Uncomment for testing wifi manager
// wifiManager.resetSettings();
wifiManager.setAPCallback(configModeCallback);
//or use this for auto generated name ESP + ChipID
wifiManager.autoConnect();
//Manual Wifi
// WiFi.begin(SSID, PASSWORD);
String hostname(HOSTNAME);
WiFi.hostname(hostname);
int counter = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
display.clear();
display.drawString(64, 10, "Connecting to WiFi");
display.drawXbm(46, 30, 8, 8, counter % 3 == 0 ? activeSymbol : inactiveSymbol);
display.drawXbm(60, 30, 8, 8, counter % 3 == 1 ? activeSymbol : inactiveSymbol);
display.drawXbm(74, 30, 8, 8, counter % 3 == 2 ? activeSymbol : inactiveSymbol);
display.display();
counter++;
}
ui.setTargetFPS(60);
ui.setTimePerFrame(8*1000); // Setup frame display time to 10 sec
//Hack until disableIndicator works:
//Set an empty symbol
ui.setActiveSymbol(emptySymbol);
ui.setInactiveSymbol(emptySymbol);
ui.disableIndicator();
// You can change the transition that is used
// SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
ui.setFrameAnimation(SLIDE_LEFT);
ui.setFrames(frames, numberOfFrames);
ui.setOverlays(overlays, numberOfOverlays);
// Setup OTA
Serial.println("Hostname: " + hostname);
ArduinoOTA.setHostname((const char *)hostname.c_str());
ArduinoOTA.onProgress(drawOtaProgress);
ArduinoOTA.begin();
updateData(&display);
ticker.attach(UPDATE_INTERVAL_SECS, setReadyForWeatherUpdate);
ticker.attach(10, setReadyForIndoorUpdate);
mqttClient.set_server("server.com", 1883);
}
void loop() {
if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
updateData(&display);
}
if (readyForIndoorUpdate && ui.getUiState()->frameState == FIXED) {
updateIndoor();
}
int remainingTimeBudget = ui.update();
if (remainingTimeBudget > 0) {
// You can do some work here
// Don't do stuff if you are below your
// time budget.
ArduinoOTA.handle();
if (!mqttClient.connected()) {
if(lastMQTTConnectionAttempt == 0 || millis() > lastMQTTConnectionAttempt + 10 * 60 * 1000) {
lastMQTTConnectionAttempt = millis();
Serial.println(millis());
Serial.println("Trying to connect to mqtt");
if (mqttClient.connect("spk-sauron")) {
Serial.println("connected");
} else {
Serial.println("failed");
}
}
} else {
mqttClient.loop();
}
delay(remainingTimeBudget);
}
}
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println("Entered config mode");
Serial.println(WiFi.softAPIP());
//if you used auto generated SSID, print it
Serial.println(myWiFiManager->getConfigPortalSSID());
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_10);
display.drawString(64, 10, "Wifi Manager");
display.drawString(64, 20, "Please connect to AP");
display.drawString(64, 30, myWiFiManager->getConfigPortalSSID());
display.drawString(64, 40, "To setup Wifi Configuration");
display.display();
}
void drawProgress(OLEDDisplay *display, int percentage, String label) {
display->clear();
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(64, 10, label);
display->drawProgressBar(2, 28, 124, 12, percentage);
display->display();
}
void drawOtaProgress(unsigned int progress, unsigned int total) {
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_10);
display.drawString(64, 10, "OTA Update");
display.drawProgressBar(2, 28, 124, 12, progress / (total / 100));
display.display();
}
void updateData(OLEDDisplay *display) {
drawProgress(display, 10, "Updating time...");
configTime(UTC_OFFSET * 3600, 0, NTP_SERVERS);
drawProgress(display, 30, "Updating conditions...");
wunderground.updateConditions(WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
drawProgress(display, 50, "Updating forecasts...");
wunderground.updateForecast(WUNDERGRROUND_API_KEY, WUNDERGRROUND_LANGUAGE, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY);
//drawProgress(display, 70, "Updating DHT Sensor");
// humidity = dht.readHumidity();
drawProgress(display, 80, "Updating Sensors...");
temperature = bme.readTemperature();
delay(500);
drawProgress(display, 90, "Updating thingspeak...");
// thingspeak.getLastChannelItem(THINGSPEAK_CHANNEL_ID, THINGSPEAK_API_READ_KEY);
readyForWeatherUpdate = false;
drawProgress(display, 100, "Done...");
delay(1000);
}
// Called every 1 minute
void updateIndoor() {
temperature = bme.readTemperature();
char topic[50];
sprintf(topic, "homie/sauron/temperature/degrees");
String stateString = String(temperature);
mqttClient.publish(topic, stateString);
readyForIndoorUpdate = false;
}
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
char *dstAbbrev;
char time_str[11];
time_t now = dstAdjusted.time(&dstAbbrev);
struct tm * timeinfo = localtime (&now);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
String date = ctime(&now);
date = date.substring(0,11) + String(1900+timeinfo->tm_year);
int textWidth = display->getStringWidth(date);
display->drawString(64 + x, 5 + y, date);
display->setFont(DSEG7_Classic_Bold_21);
display->setTextAlignment(TEXT_ALIGN_RIGHT);
#ifdef STYLE_24HR
sprintf(time_str, "%02d:%02d:%02d\n",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
display->drawString(108 + x, 19 + y, time_str);
#else
int hour = (timeinfo->tm_hour+11)%12+1; // take care of noon and midnight
sprintf(time_str, "%2d:%02d:%02d\n",hour, timeinfo->tm_min, timeinfo->tm_sec);
display->drawString(101 + x, 19 + y, time_str);
#endif
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
#ifdef STYLE_24HR
sprintf(time_str, "%s", dstAbbrev);
display->drawString(108 + x, 27 + y, time_str); // Known bug: Cuts off 4th character of timezone abbreviation
#else
sprintf(time_str, "%s\n%s", dstAbbrev, timeinfo->tm_hour>=12?"pm":"am");
display->drawString(102 + x, 18 + y, time_str);
#endif
}
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
display->setFont(ArialMT_Plain_10);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(60 + x, 5 + y, wunderground.getWeatherText());
display->setFont(ArialMT_Plain_24);
String temp = wunderground.getCurrentTemp() + (IS_METRIC ? "°C": "°F");
display->drawString(60 + x, 15 + y, temp);
int tempWidth = display->getStringWidth(temp);
display->setFont(Meteocons_Plain_42);
String weatherIcon = wunderground.getTodayIcon();
int weatherIconWidth = display->getStringWidth(weatherIcon);
display->drawString(32 + x - weatherIconWidth / 2, 05 + y, weatherIcon);
}
void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
drawForecastDetails(display, x, y, 0);
drawForecastDetails(display, x + 44, y, 2);
drawForecastDetails(display, x + 88, y, 4);
}
void drawForecast2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
drawForecastDetails(display, x, y, 6);
drawForecastDetails(display, x + 44, y, 8);
drawForecastDetails(display, x + 88, y, 10);
}
void drawIndoor(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(64 + x, y + 5, "Indoor" );
display->setFont(ArialMT_Plain_24);
dtostrf(temperature, 4, 1, FormattedTemperature);
display->drawString(64 + x, y + 19, "" + String(FormattedTemperature) + (IS_METRIC ? "°C": "°F"));
//dtostrf(humidity,4, 1, FormattedHumidity);
//display->drawString(64+x, 30, "Humidity: " + String(FormattedHumidity) + "%");
}
void drawThingspeak(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(64 + x, 0 + y, "Thingspeak Sensor");
display->setFont(ArialMT_Plain_16);
display->drawString(64 + x, 12 + y, thingspeak.getFieldValue(0) + "°C");
// display->drawString(64 + x, 12 + y, thingspeak.getFieldValue(0) + (IS_METRIC ? "°C": "°F")); // Needs code to convert Thingspeak temperature string
display->drawString(64 + x, 30 + y, thingspeak.getFieldValue(1) + "%");
}
void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
String day = wunderground.getForecastTitle(dayIndex).substring(0, 3);
day.toUpperCase();
display->drawString(x + 20, y, day);
display->setFont(Meteocons_Plain_21);
display->drawString(x + 20, y + 12, wunderground.getForecastIcon(dayIndex));
display->setFont(ArialMT_Plain_10);
display->drawString(x + 20, y + 34, wunderground.getForecastLowTemp(dayIndex) + "|" + wunderground.getForecastHighTemp(dayIndex));
display->setTextAlignment(TEXT_ALIGN_LEFT);
}
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
int y = 55;
display->setColor(WHITE);
display->fillRect(0, y, 128, 9);
display->setColor(BLACK);
display->setFont(ArialMT_Plain_10);
char time_str[11];
time_t now = dstAdjusted.time(nullptr);
struct tm * timeinfo = localtime (&now);
display->setFont(ArialMT_Plain_10);
#ifdef STYLE_24HR
sprintf(time_str, "%02d:%02d:%02d\n",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
#else
int hour = (timeinfo->tm_hour+11)%12+1; // take care of noon and midnight
sprintf(time_str, "%2d:%02d:%02d%s\n",hour, timeinfo->tm_min, timeinfo->tm_sec, timeinfo->tm_hour>=12?"pm":"am");
#endif
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64, y - 2, time_str);
display->setTextAlignment(TEXT_ALIGN_RIGHT);
dtostrf(temperature, 4, 1, FormattedTemperature);
display->drawString(128, y - 2, "" + String(FormattedTemperature) + (IS_METRIC ? "°C": "°F"));
int8_t quality = getWifiQuality();
for (int8_t i = 0; i < 4; i++) {
if (quality > i * 25) {
display->drawCircle(4 + 8 * i, y + 4, 3);
} else {
display->fillCircle(4 + 8 * i, y + 4, 3);
}
}
display->setColor(WHITE);
}
/*
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
char time_str[11];
time_t now = dstAdjusted.time(nullptr);
struct tm * timeinfo = localtime (&now);
display->setFont(ArialMT_Plain_10);
#ifdef STYLE_24HR
sprintf(time_str, "%02d:%02d:%02d\n",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
#else
int hour = (timeinfo->tm_hour+11)%12+1; // take care of noon and midnight
sprintf(time_str, "%2d:%02d:%02d%s\n",hour, timeinfo->tm_min, timeinfo->tm_sec, timeinfo->tm_hour>=12?"pm":"am");
#endif
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(5, 52, time_str);
display->setTextAlignment(TEXT_ALIGN_CENTER);
String temp = wunderground.getCurrentTemp() + (IS_METRIC ? "°C": "°F");
display->drawString(101, 52, temp);
int8_t quality = getWifiQuality();
for (int8_t i = 0; i < 4; i++) {
for (int8_t j = 0; j < 2 * (i + 1); j++) {
if (quality > i * 25 || j == 0) {
display->setPixel(120 + 2 * i, 61 - j);
}
}
}
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(Meteocons_Plain_10);
String weatherIcon = wunderground.getTodayIcon();
int weatherIconWidth = display->getStringWidth(weatherIcon);
// display->drawString(64, 55, weatherIcon);
display->drawString(77, 53, weatherIcon);
display->drawHorizontalLine(0, 51, 128);
}
*/
// converts the dBm to a range between 0 and 100%
int8_t getWifiQuality() {
int32_t dbm = WiFi.RSSI();
if(dbm <= -100) {
return 0;
} else if(dbm >= -50) {
return 100;
} else {
return 2 * (dbm + 100);
}
}
void setReadyForWeatherUpdate() {
Serial.println("Setting readyForUpdate to true");
readyForWeatherUpdate = true;
}
void setReadyForIndoorUpdate() {
Serial.println("Setting setReadyForIndoorUpdate to true");
readyForIndoorUpdate = true;
}
Basic Infos
Hi! If it would be possible for someone with knowledge (which I do not have) to create a better AutoConnectNonBlocking-example-file ? It wold be really appreciated and helpful with an example where some code is executed during the "Portal Mode" and also shown how to know when exiting the portal.
I know there are some info here: https://github.com/tzapu/WiFiManager#save-settings But I do not manage to get it working. Example files are the best!
Would be really nice to reach the goal to urge someone to connect to WiFi: x with Password: y with a simple message on a display. And Finally a message "Device connected!" or something similar..
Searched the web for hours, and all I can find is others who not succeed either. So no code to "borrow" from someone. :-( And the "NonBlocking" is needed to be able to toggle between messages if I got it right.
I supply my sketchy sketch which almost gets me there. And no, I do not consider me as a programmer. Haha!. It must be a smarter way?
Hardware
WiFimanager Branch/Release: Master
Esp8266/Esp32:
Hardware: ESP-12e, esp01, esp25
Core Version: 2.4.0, staging
Description
Problem description
Settings in IDE
Module: NodeMcu, Wemos D1
Additional libraries:
Sketch
Debug Messages