body:
With ESP8266, I noticed that for the first 1 or 2 loops, `localtime` returns Unix epoch (1970 date) until it has finished getting the actual time from NTP, after which point I see the real date. Sometimes it can take 10 seconds or so before NTP is available, depending on what time server I use and how frequently I make requests to it (most time servers have request throttling, it seems).

Right now, I'm checking whether the date is valid by testing if the year is `70` but this seems weird and hacky. Is there a better way? For instance, is there a function that returns `true` if the NTP update has been successful or `-1` if not?

All of the examples of `localtime` that I have found so far don't seem to check if the date is valid, and if I run their code, it almost always prints the 1970 Unix epoch date on the first loop.

```
#define TIME_SERVER_1 "time.google.com"
#define TIME_SERVER_2 "time.nist.gov"
#define TIME_SERVER_3 "pool.ntp.org"
#define TIMEZONE TZ_Europe_London

void setup() {

// ..

  configTime(TIMEZONE, TIME_SERVER_1, TIME_SERVER_2, TIME_SERVER_3);

// ..

}

void loop() {

// ..

      time_t now;
      time(&now);
      struct tm* timeinfo = localtime(&now);

      // TODO: maybe there's a better way to check unknown time?
      if (timeinfo->tm_year == 70) {
        TRACE_LN(F("ntp not yet available"));
      } else {
        epoch = mktime(timeinfo);
      }

//..

}
```

title: What is the ideal way to check if time on ESP8266 via NTP is ready?

Answers: 4

body:
If `time()` doesn't return `-1` as expected when it doesn't know, then I
have nothing cleaner (less “hacky”) to suggest. That being said,
converting the scalar time to a broken-down representation is a
relatively expensive operation. I suggest avoiding it and just comparing
the returned time to an arbitrary threshold:

```c++
// May we consider this valid as the "current" time?
// If it is too far in the past, it is centainly not valid.
static bool is_time_valid(time_t t) {
    const time_t old_past = 1577836800;  // 2020-01-01T00:00:00Z
    return t >= old_past;
}
```

body:
You can define a call back function which is triggered when SNTP updates the system time. There is an example of it on the [GitHub esp8266/Arduino project][1] with a short description in the comments. The call back function is registered by the example function call `settimeofday_cb(time_is_set)` where time_is_set() is a user defined funtion.

I have an application (a timeswitch) which maintains an indicator to show how 'fresh' the current time status is. If it is stale, the time source reverts to an RTC until a new time can be fetched. It uses this callback mechanism for that purpose.

  [1]: https://github.com/esp8266/Arduino/blob/da48a52d7a8854363946fe0c05f02ec029c852c5/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino#L241

body:
The following code snippet is most likely the best way of ensuring valid time from NTP. If the call to timeSetup(...) is made after already connected to the internet, then that connection will be used, otherwise the setup will connect to internet, using passed in credetials, and when finished getting NTP time, will disconnect. The code has been cut/pasted from a much bigger project and has not been tested, so there might be some syntax errors.

**The SNTP stuff:**

    #include "sntp.h"
    #include "time.h"
    #include <sys/time.h>
    #include <WiFi.h>

    int WiFiconnectedhere = 0;
    int timeIsSet = 0;

    // timeavailable() cannot be in a class has to be static
    //callback function when time has been set
    void timeavailable(struct timeval *t)
    {
      struct tm timeinfo;
      Serial.println("NTP notification that time is set");

      if (!getLocalTime(&timeinfo)){
        Serial.println("Using getLocalTime()No time available (yet)");
        return;
      }
      Serial.println(&timeinfo, "using getLocalTime() = %A, %B %d %Y   H:%M:%S");

      if (WiFiconnectedhere == 1) {
        WiFi.disconnect(true, true);  //WiFi off, erase AP
        WiFiconnectedhere = 0;
        Serial.println("WiFi has been disconnected");
      }
      timeIsSet = 1;
    }

    void ESP32Time::timeSetup(
        char *ssid,
        char *password,
        char *ntpServer1,
        char *ntpServer2,
        char *timezone)
    {
      timeIsSet = 0;
      //connect to WiFi if not already connected
      if (! WiFi.isConnected()) {  //standard WiFi call to check if connected
        sntp_servermode_dhcp(1);    // (optional)
        Serial.printf("Connecting to %s in time module\r\n", ssid);
        WiFi.begin(ssid, password);
        while (WiFi.status() != WL_CONNECTED) {
            delay(500);
            Serial.print(".");
        }
        Serial.printf(" CONNECTED to internet %s\r\n", ssid);
        WiFiconnectedhere = 1; // so we know to disconnect after done with it
      }
      else {
        Serial.println("WiFi is already connected");
      }

      // get a callback when time has been received locally
      sntp_set_time_sync_notification_cb( timeavailable );

      configTzTime(timezone, ntpServer1, ntpServer2);
      Serial.println("Getting localtime");
      setenv("TZ", timezone, 1);
      tzset();

    }

**Usage**:

    ESP32Time esptime;  // Instantiate the class

In arduino setup()

    //initialise the time.
    esptime.timeSetup(ssid, password, ntpserver1, ntpserver2, timezone);

**Retrieve local time:**

      struct tm timeinfo;
      time_t now;
      time(&now);
      localtime_r(&now, &timeinfo);
      time_t tt = mktime (&timeinfo);

****The timezones in a program usable array (sorry it is so long):****

    #ifndef TZDB_H
    #define TZDB_H

    typedef struct {
      char tzlit[35];
      char tzzone[45];
    } tTimezones;

    #ifndef TZARRAY
    #define TZARRAY

    tTimezones tz[470] =
    {
    {"TZ_Africa_Abidjan ","GMT0"},
    {"TZ_Africa_Accra " , "GMT0"},
    {"TZ_Africa_Addis_Ababa ","EAT-3"},
    {"TZ_Africa_Algiers ","CET-1"},
    {"TZ_Africa_Asmara ","EAT-3"},
    {"TZ_Africa_Bamako ","GMT0"},
    {"TZ_Africa_Bangui ","WAT-1"},
    {"TZ_Africa_Banjul ","GMT0"},
    {"TZ_Africa_Bissau ","GMT0"},
    {"TZ_Africa_Blantyre ","CAT-2"},
    {"TZ_Africa_Brazzaville ","WAT-1"},
    {"TZ_Africa_Bujumbura ","CAT-2"},
    {"TZ_Africa_Cairo ","EET-2"},
    {"TZ_Africa_Casablanca ","<+01>-1"},
    {"TZ_Africa_Ceuta ","CET-1CEST,M3.5.0,M10.5.0/3"},
    {"TZ_Africa_Conakry ","GMT0"},
    {"TZ_Africa_Dakar ","GMT0"},
    {"TZ_Africa_Dar_es_Salaam ","EAT-3"},
    {"TZ_Africa_Djibouti ","EAT-3"},
    {"TZ_Africa_Douala ","WAT-1"},
    {"TZ_Africa_El_Aaiun ","<+01>-1"},
    {"TZ_Africa_Freetown ","GMT0"},
    {"TZ_Africa_Gaborone ","CAT-2"},
    {"TZ_Africa_Harare ","CAT-2"},
    {"TZ_Africa_Johannesburg ","SAST-2"},
    {"TZ_Africa_Juba ","CAT-2"},
    {"TZ_Africa_Kampala ","EAT-3"},
    {"TZ_Africa_Khartoum ","CAT-2"},
    {"TZ_Africa_Kigali ","CAT-2"},
    {"TZ_Africa_Kinshasa ","WAT-1"},
    {"TZ_Africa_Lagos ","WAT-1"},
    {"TZ_Africa_Libreville ","WAT-1"},
    {"TZ_Africa_Lome ","GMT0"},
    {"TZ_Africa_Luanda ","WAT-1"},
    {"TZ_Africa_Lubumbashi ","CAT-2"},
    {"TZ_Africa_Lusaka ","CAT-2"},
    {"TZ_Africa_Malabo ","WAT-1"},
    {"TZ_Africa_Maputo ","CAT-2"},
    {"TZ_Africa_Maseru ","SAST-2"},
    {"TZ_Africa_Mbabane ","SAST-2"},
    {"TZ_Africa_Mogadishu ","EAT-3"},
    {"TZ_Africa_Monrovia ","GMT0"},
    {"TZ_Africa_Nairobi ","EAT-3"},
    {"TZ_Africa_Ndjamena ","WAT-1"},
    {"TZ_Africa_Niamey ","WAT-1"},
    {"TZ_Africa_Nouakchott ","GMT0"},
    {"TZ_Africa_Ouagadougou ","GMT0"},
    {"TZ_Africa_PortomNovo ","WAT-1"},
    {"TZ_Africa_Sao_Tome ","GMT0"},
    {"TZ_Africa_Tripoli ","EET-2"},
    {"TZ_Africa_Tunis ","CET-1"},
    {"TZ_Africa_Windhoek ","CAT-2"},
    {"TZ_America_Adak ","HST10HDT,M3.2.0,M11.1.0"},
    {"TZ_America_Anchorage ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Anguilla ","AST4"},
    {"TZ_America_Antigua ","AST4"},
    {"TZ_America_Araguaina ","<-03>3"},
    {"TZ_America_Argentina_Buenos_Aires ","<-03>3"},
    {"TZ_America_Argentina_Catamarca ","<-03>3"},
    {"TZ_America_Argentina_Cordoba ","<-03>3"},
    {"TZ_America_Argentina_Jujuy ","<-03>3"},
    {"TZ_America_Argentina_La_Rioja ","<-03>3"},
    {"TZ_America_Argentina_Mendoza ","<-03>3"},
    {"TZ_America_Argentina_Rio_Gallegos ","<-03>3"},
    {"TZ_America_Argentina_Salta ","<-03>3"},
    {"TZ_America_Argentina_San_Juan ","<-03>3"},
    {"TZ_America_Argentina_San_Luis ","<-03>3"},
    {"TZ_America_Argentina_Tucuman ","<-03>3"},
    {"TZ_America_Argentina_Ushuaia ","<-03>3"},
    {"TZ_America_Aruba ","AST4"},
    {"TZ_America_Asuncion ","<-04>4<-03>,M10.1.0/0,M3.4.0/0"},
    {"TZ_America_Atikokan ","EST5"},
    {"TZ_America_Bahia ","<-03>3"},
    {"TZ_America_Bahia_Banderas ","CST6"},
    {"TZ_America_Barbados ","AST4"},
    {"TZ_America_Belem ","<-03>3"},
    {"TZ_America_Belize ","CST6"},
    {"TZ_America_BlancmSablon ","AST4"},
    {"TZ_America_Boa_Vista ","<-04>4"},
    {"TZ_America_Bogota ","<-05>5"},
    {"TZ_America_Boise ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Cambridge_Bay ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Campo_Grande ","<-04>4"},
    {"TZ_America_Cancun ","EST5"},
    {"TZ_America_Caracas ","<-04>4"},
    {"TZ_America_Cayenne ","<-03>3"},
    {"TZ_America_Cayman ","EST5"},
    {"TZ_America_Chicago ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Chihuahua ","CST6"},
    {"TZ_America_Costa_Rica ","CST6"},
    {"TZ_America_Creston ","MST7"},
    {"TZ_America_Cuiaba ","<-04>4"},
    {"TZ_America_Curacao ","AST4"},
    {"TZ_America_Danmarkshavn ","GMT0"},
    {"TZ_America_Dawson ","MST7"},
    {"TZ_America_Dawson_Creek ","MST7"},
    {"TZ_America_Denver ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Detroit ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Dominica ","AST4"},
    {"TZ_America_Edmonton ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Eirunepe ","<-05>5"},
    {"TZ_America_El_Salvador ","CST6"},
    {"TZ_America_Fortaleza ","<-03>3"},
    {"TZ_America_Fort_Nelson ","MST7"},
    {"TZ_America_Glace_Bay ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Godthab ","<-02>2"},
    {"TZ_America_Goose_Bay ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Grand_Turk ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Grenada ","AST4"},
    {"TZ_America_Guadeloupe ","AST4"},
    {"TZ_America_Guatemala ","CST6"},
    {"TZ_America_Guayaquil ","<-05>5"},
    {"TZ_America_Guyana ","<-04>4"},
    {"TZ_America_Halifax ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Havana ","CST5CDT,M3.2.0/0,M11.1.0/1"},
    {"TZ_America_Hermosillo ","MST7"},
    {"TZ_America_Indiana_Indianapolis ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Knox ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Marengo ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Petersburg ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Tell_City ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Vevay ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Vincennes ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Indiana_Winamac ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Inuvik ","MST7MDT,M3.2.0,M11.1.0"},
    {"TZ_America_Iqaluit ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Jamaica ","EST5"},
    {"TZ_America_Juneau ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Kentucky_Louisville ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Kentucky_Monticello ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Kralendijk ","AST4"},
    {"TZ_America_La_Paz ","<-04>4"},
    {"TZ_America_Lima ","<-05>5"},
    {"TZ_America_Los_Angeles ","PST8PDT,M3.2.0,M11.1.0"},
    {"TZ_America_Lower_Princes ","AST4"},
    {"TZ_America_Maceio ","<-03>3"},
    {"TZ_America_Managua ","CST6"},
    {"TZ_America_Manaus ","<-04>4"},
    {"TZ_America_Marigot ","AST4"},
    {"TZ_America_Martinique ","AST4"},
    {"TZ_America_Matamoros ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Mazatlan ","MST7"},
    {"TZ_America_Menominee ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Merida ","CST6"},
    {"TZ_America_Metlakatla ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Mexico_City ","CST6"},
    {"TZ_America_Miquelon ","<-03>3<-02>,M3.2.0,M11.1.0"},
    {"TZ_America_Moncton ","AST4ADT,M3.2.0,M11.1.0"},
    {"TZ_America_Monterrey ","CST6"},
    {"TZ_America_Montevideo ","<-03>3"},
    {"TZ_America_Montreal ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Montserrat ","AST4"},
    {"TZ_America_Nassau ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_New_York ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Nipigon ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Nome ","AKST9AKDT,M3.2.0,M11.1.0"},
    {"TZ_America_Noronha ","<-02>2"},
    {"TZ_America_North_Dakota_Beulah ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_North_Dakota_Center ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_North_Dakota_New_Salem ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Nuuk ","<-02>2"},
    {"TZ_America_Ojinaga ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Panama ","EST5"},
    {"TZ_America_Pangnirtung ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Paramaribo ","<-03>3"},
    {"TZ_America_Phoenix ","MST7"},
    {"TZ_America_PortmaumPrince ","EST5EDT,M3.2.0,M11.1.0"},
    {"TZ_America_Port_of_Spain ","AST4"},
    {"TZ_America_Porto_Velho ","<-04>4"},
    {"TZ_America_Puerto_Rico ","AST4"},
    {"TZ_America_Punta_Arenas ","<-03>3"},
    {"TZ_America_Rainy_River ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Rankin_Inlet ","CST6CDT,M3.2.0,M11.1.0"},
    {"TZ_America_Recife ","<-03>3"},
    {"TZ_America_Regina ","CST6"},
    {"TZ_America_Resolute ","CST6CDT,M3.2.0,M11.1.0"},

body:
**Continuation of timezones:**

```{"TZ_America_Rio_Branco ","<-05>5"},
        {"TZ_America_Santarem ","<-03>3"},
        {"TZ_America_Santiago ","<-04>4<-03>,M9.1.6/24,M4.1.6/24"},
        {"TZ_America_Santo_Domingo ","AST4"},
        {"TZ_America_Sao_Paulo ","<-03>3"},
        {"TZ_America_Scoresbysund ","<-01>1<+00>,M3.5.0/0,M10.5.0/1"},
        {"TZ_America_Sitka ","AKST9AKDT,M3.2.0,M11.1.0"},
        {"TZ_America_St_Barthelemy ","AST4"},
        {"TZ_America_St_Johns ","NST3:30NDT,M3.2.0,M11.1.0"},
        {"TZ_America_St_Kitts ","AST4"},
        {"TZ_America_St_Lucia ","AST4"},
        {"TZ_America_St_Thomas ","AST4"},
        {"TZ_America_St_Vincent ","AST4"},
        {"TZ_America_Swift_Current ","CST6"},
        {"TZ_America_Tegucigalpa ","CST6"},
        {"TZ_America_Thule ","AST4ADT,M3.2.0,M11.1.0"},
        {"TZ_America_Thunder_Bay ","EST5EDT,M3.2.0,M11.1.0"},
        {"TZ_America_Tijuana ","PST8PDT,M3.2.0,M11.1.0"},
        {"TZ_America_Toronto ","EST5EDT,M3.2.0,M11.1.0"},
        {"TZ_America_Tortola ","AST4"},
        {"TZ_America_Vancouver ","PST8PDT,M3.2.0,M11.1.0"},
        {"TZ_America_Whitehorse ","MST7"},
        {"TZ_America_Winnipeg ","CST6CDT,M3.2.0,M11.1.0"},
        {"TZ_America_Yakutat ","AKST9AKDT,M3.2.0,M11.1.0"},
        {"TZ_America_Yellowknife ","MST7MDT,M3.2.0,M11.1.0"},
        {"TZ_Antarctica_Casey ","<+11>-11"},
        {"TZ_Antarctica_Davis ","<+07>-7"},
        {"TZ_Antarctica_DumontDUrville ","<+10>-10"},
        {"TZ_Antarctica_Macquarie ","AEST-10AEDT,M10.1.0,M4.1.0/3"},
        {"TZ_Antarctica_Mawson ","<+05>-5"},
        {"TZ_Antarctica_McMurdo ","NZST-12NZDT,M9.5.0,M4.1.0/3"},
        {"TZ_Antarctica_Palmer ","<-03>3"},
        {"TZ_Antarctica_Rothera ","<-03>3"},
        {"TZ_Antarctica_Syowa ","<+03>-3"},
        {"TZ_Antarctica_Troll ","<+00>0<+02>-2,M3.5.0/1,M10.5.0/3"},
        {"TZ_Antarctica_Vostok ","<+06>-6"},
        {"TZ_Arctic_Longyearbyen ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Asia_Aden ","<+03>-3"},
        {"TZ_Asia_Almaty ","<+06>-6"},
        {"TZ_Asia_Amman ","<+03>-3"},
        {"TZ_Asia_Anadyr ","<+12>-12"},
        {"TZ_Asia_Aqtau ","<+05>-5"},
        {"TZ_Asia_Aqtobe ","<+05>-5"},
        {"TZ_Asia_Ashgabat ","<+05>-5"},
        {"TZ_Asia_Atyrau ","<+05>-5"},
        {"TZ_Asia_Baghdad ","<+03>-3"},
        {"TZ_Asia_Bahrain ","<+03>-3"},
        {"TZ_Asia_Baku ","<+04>-4"},
        {"TZ_Asia_Bangkok ","<+07>-7"},
        {"TZ_Asia_Barnaul ","<+07>-7"},
        {"TZ_Asia_Beirut ","EET-2EEST,M3.5.0/0,M10.5.0/0"},
        {"TZ_Asia_Bishkek ","<+06>-6"},
        {"TZ_Asia_Brunei ","<+08>-8"},
        {"TZ_Asia_Chita ","<+09>-9"},
        {"TZ_Asia_Choibalsan ","<+08>-8"},
        {"TZ_Asia_Colombo ","<+0530>-5:30"},
        {"TZ_Asia_Damascus ","<+03>-3"},
        {"TZ_Asia_Dhaka ","<+06>-6"},
        {"TZ_Asia_Dili ","<+09>-9"},
        {"TZ_Asia_Dubai ","<+04>-4"},
        {"TZ_Asia_Dushanbe ","<+05>-5"},
        {"TZ_Asia_Famagusta ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Asia_Gaza ","EET-2EEST,M3.4.4/50,M10.4.4/50"},
        {"TZ_Asia_Hebron ","EET-2EEST,M3.4.4/50,M10.4.4/50"},
        {"TZ_Asia_Ho_Chi_Minh ","<+07>-7"},
        {"TZ_Asia_Hong_Kong ","HKT-8"},
        {"TZ_Asia_Hovd ","<+07>-7"},
        {"TZ_Asia_Irkutsk ","<+08>-8"},
        {"TZ_Asia_Jakarta ","WIB-7"},
        {"TZ_Asia_Jayapura ","WIT-9"},
        {"TZ_Asia_Jerusalem ","IST-2IDT,M3.4.4/26,M10.5.0"},
        {"TZ_Asia_Kabul ","<+0430>-4:30"},
        {"TZ_Asia_Kamchatka ","<+12>-12"},
        {"TZ_Asia_Karachi ","PKT-5"},
        {"TZ_Asia_Kathmandu ","<+0545>-5:45"},
        {"TZ_Asia_Khandyga ","<+09>-9"},
        {"TZ_Asia_Kolkata ","IST-5:30"},
        {"TZ_Asia_Krasnoyarsk ","<+07>-7"},
        {"TZ_Asia_Kuala_Lumpur ","<+08>-8"},
        {"TZ_Asia_Kuching ","<+08>-8"},
        {"TZ_Asia_Kuwait ","<+03>-3"},
        {"TZ_Asia_Macau ","CST-8"},
        {"TZ_Asia_Magadan ","<+11>-11"},
        {"TZ_Asia_Makassar ","WITA-8"},
        {"TZ_Asia_Manila ","PST-8"},
        {"TZ_Asia_Muscat ","<+04>-4"},
        {"TZ_Asia_Nicosia ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Asia_Novokuznetsk ","<+07>-7"},
        {"TZ_Asia_Novosibirsk ","<+07>-7"},
        {"TZ_Asia_Omsk ","<+06>-6"},
        {"TZ_Asia_Oral ","<+05>-5"},
        {"TZ_Asia_Phnom_Penh ","<+07>-7"},
        {"TZ_Asia_Pontianak ","WIB-7"},
        {"TZ_Asia_Pyongyang ","KST-9"},
        {"TZ_Asia_Qatar ","<+03>-3"},
        {"TZ_Asia_Qyzylorda ","<+05>-5"},
        {"TZ_Asia_Riyadh ","<+03>-3"},
        {"TZ_Asia_Sakhalin ","<+11>-11"},
        {"TZ_Asia_Samarkand ","<+05>-5"},
        {"TZ_Asia_Seoul ","KST-9"},
        {"TZ_Asia_Shanghai ","CST-8"},
        {"TZ_Asia_Singapore ","<+08>-8"},
        {"TZ_Asia_Srednekolymsk ","<+11>-11"},
        {"TZ_Asia_Taipei ","CST-8"},
        {"TZ_Asia_Tashkent ","<+05>-5"},
        {"TZ_Asia_Tbilisi ","<+04>-4"},
        {"TZ_Asia_Tehran ","<+0330>-3:30"},
        {"TZ_Asia_Thimphu ","<+06>-6"},
        {"TZ_Asia_Tokyo ","JST-9"},
        {"TZ_Asia_Tomsk ","<+07>-7"},
        {"TZ_Asia_Ulaanbaatar ","<+08>-8"},
        {"TZ_Asia_Urumqi ","<+06>-6"},
        {"TZ_Asia_UstmNera ","<+10>-10"},
        {"TZ_Asia_Vientiane ","<+07>-7"},
        {"TZ_Asia_Vladivostok ","<+10>-10"},
        {"TZ_Asia_Yakutsk ","<+09>-9"},
        {"TZ_Asia_Yangon ","<+0630>-6:30"},
        {"TZ_Asia_Yekaterinburg ","<+05>-5"},
        {"TZ_Asia_Yerevan ","<+04>-4"},
        {"TZ_Atlantic_Azores ","<-01>1<+00>,M3.5.0/0,M10.5.0/1"},
        {"TZ_Atlantic_Bermuda ","AST4ADT,M3.2.0,M11.1.0"},
        {"TZ_Atlantic_Canary ","WET0WEST,M3.5.0/1,M10.5.0"},
        {"TZ_Atlantic_Cape_Verde ","<-01>1"},
        {"TZ_Atlantic_Faroe ","WET0WEST,M3.5.0/1,M10.5.0"},
        {"TZ_Atlantic_Madeira ","WET0WEST,M3.5.0/1,M10.5.0"},
        {"TZ_Atlantic_Reykjavik ","GMT0"},
        {"TZ_Atlantic_South_Georgia ","<-02>2"},
        {"TZ_Atlantic_Stanley ","<-03>3"},
        {"TZ_Atlantic_St_Helena ","GMT0"},
        {"TZ_Australia_Adelaide ","ACST-9:30ACDT,M10.1.0,M4.1.0/3"},
        {"TZ_Australia_Brisbane ","AEST-10"},
        {"TZ_Australia_Broken_Hill ","ACST-9:30ACDT,M10.1.0,M4.1.0/3"},
        {"TZ_Australia_Currie ","AEST-10AEDT,M10.1.0,M4.1.0/3"},
        {"TZ_Australia_Darwin ","ACST-9:30"},
        {"TZ_Australia_Eucla ","<+0845>-8:45"},
        {"TZ_Australia_Hobart ","AEST-10AEDT,M10.1.0,M4.1.0/3"},
        {"TZ_Australia_Lindeman ","AEST-10"},
        {"TZ_Australia_Lord_Howe ","<+1030>-10:30<+11>-11,M10.1.0,M4.1.0"},
        {"TZ_Australia_Melbourne ","AEST-10AEDT,M10.1.0,M4.1.0/3"},
        {"TZ_Australia_Perth ","AWST-8"},
        {"TZ_Australia_Sydney ","AEST-10AEDT,M10.1.0,M4.1.0/3"},
        {"TZ_Europe_Amsterdam ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Andorra ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Astrakhan ","<+04>-4"},
        {"TZ_Europe_Athens ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Belgrade ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Berlin ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Bratislava ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Brussels ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Bucharest ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Budapest ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Busingen ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Chisinau ","EET-2EEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Copenhagen ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Dublin ","IST-1GMT0,M10.5.0,M3.5.0/1"},
        {"TZ_Europe_Gibraltar ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Guernsey ","GMT0BST,M3.5.0/1,M10.5.0"},
        {"TZ_Europe_Helsinki ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Isle_of_Man ","GMT0BST,M3.5.0/1,M10.5.0"},
        {"TZ_Europe_Istanbul ","<+03>-3"},
        {"TZ_Europe_Jersey ","GMT0BST,M3.5.0/1,M10.5.0"},
        {"TZ_Europe_Kaliningrad ","EET-2"},
        {"TZ_Europe_Kiev ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Kirov ","<+03>-3"},
        {"TZ_Europe_Lisbon ","WET0WEST,M3.5.0/1,M10.5.0"},
        {"TZ_Europe_Ljubljana ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_London ","GMT0BST,M3.5.0/1,M10.5.0"},
        {"TZ_Europe_Luxembourg ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Madrid ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Malta ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Mariehamn ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Minsk ","<+03>-3"},
        {"TZ_Europe_Monaco ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Moscow ","MSK-3"},
        {"TZ_Europe_Oslo ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Paris ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Podgorica ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Prague ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Riga ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Rome ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Samara ","<+04>-4"},
        {"TZ_Europe_San_Marino ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Sarajevo ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Saratov ","<+04>-4"},
        {"TZ_Europe_Simferopol ","MSK-3"},
        {"TZ_Europe_Skopje ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Sofia ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Stockholm ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Tallinn ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Tirane ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Ulyanovsk ","<+04>-4"},
        {"TZ_Europe_Uzhgorod ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Vaduz ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Vatican ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Vienna ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Vilnius ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Volgograd ","<+03>-3"},
        {"TZ_Europe_Warsaw ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Zagreb ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Europe_Zaporozhye ","EET-2EEST,M3.5.0/3,M10.5.0/4"},
        {"TZ_Europe_Zurich ","CET-1CEST,M3.5.0,M10.5.0/3"},
        {"TZ_Indian_Antananarivo ","EAT-3"},
        {"TZ_Indian_Chagos ","<+06>-6"},
        {"TZ_Indian_Christmas ","<+07>-7"},
        {"TZ_Indian_Cocos ","<+0630>-6:30"},
        {"TZ_Indian_Comoro ","EAT-3"},
        {"TZ_Indian_Kerguelen ","<+05>-5"},
        {"TZ_Indian_Mahe ","<+04>-4"},
        {"TZ_Indian_Maldives ","<+05>-5"},
        {"TZ_Indian_Mauritius ","<+04>-4"},
        {"TZ_Indian_Mayotte ","EAT-3"},
        {"TZ_Indian_Reunion ","<+04>-4"},
        {"TZ_Pacific_Apia ","<+13>-13"},
        {"TZ_Pacific_Auckland ","NZST-12NZDT,M9.5.0,M4.1.0/3"},
        {"TZ_Pacific_Bougainville ","<+11>-11"},
        {"TZ_Pacific_Chatham ","<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45"},
        {"TZ_Pacific_Chuuk ","<+10>-10"},
        {"TZ_Pacific_Easter ","<-06>6<-05>,M9.1.6/22,M4.1.6/22"},
        {"TZ_Pacific_Efate ","<+11>-11"},
        {"TZ_Pacific_Enderbury ","<+13>-13"},
        {"TZ_Pacific_Fakaofo ","<+13>-13"},
        {"TZ_Pacific_Fiji ","<+12>-12"},
        {"TZ_Pacific_Funafuti ","<+12>-12"},
        {"TZ_Pacific_Galapagos ","<-06>6"},
        {"TZ_Pacific_Gambier ","<-09>9"},
        {"TZ_Pacific_Guadalcanal ","<+11>-11"},
        {"TZ_Pacific_Guam ","ChST-10"},
        {"TZ_Pacific_Honolulu ","HST10"},
        {"TZ_Pacific_Kiritimati ","<+14>-14"},
        {"TZ_Pacific_Kosrae ","<+11>-11"},
        {"TZ_Pacific_Kwajalein ","<+12>-12"},
        {"TZ_Pacific_Majuro ","<+12>-12"},
        {"TZ_Pacific_Marquesas ","<-0930>9:30"},
        {"TZ_Pacific_Midway ","SST11"},
        {"TZ_Pacific_Nauru ","<+12>-12"},
        {"TZ_Pacific_Niue ","<-11>11"},
        {"TZ_Pacific_Norfolk ","<+11>-11<+12>,M10.1.0,M4.1.0/3"},
        {"TZ_Pacific_Noumea ","<+11>-11"},
        {"TZ_Pacific_Pago_Pago ","SST11"},
        {"TZ_Pacific_Palau ","<+09>-9"},
        {"TZ_Pacific_Pitcairn ","<-08>8"},
        {"TZ_Pacific_Pohnpei ","<+11>-11"},
        {"TZ_Pacific_Port_Moresby ","<+10>-10"},
        {"TZ_Pacific_Rarotonga ","<-10>10"},
        {"TZ_Pacific_Saipan ","ChST-10"},
        {"TZ_Pacific_Tahiti ","<-10>10"},
        {"TZ_Pacific_Tarawa ","<+12>-12"},
        {"TZ_Pacific_Tongatapu ","<+13>-13"},
        {"TZ_Pacific_Wake ","<+12>-12"},
        {"TZ_Pacific_Wallis ","<+12>-12"},
        {"TZ_Etc_GMT ","GMT0"},
        {"TZ_Etc_GMTm0 ","GMT0"},
        {"TZ_Etc_GMTm1 ","<+01>-1"},
        {"TZ_Etc_GMTm2 ","<+02>-2"},
        {"TZ_Etc_GMTm3 ","<+03>-3"},
        {"TZ_Etc_GMTm4 ","<+04>-4"},
        {"TZ_Etc_GMTm5 ","<+05>-5"},
        {"TZ_Etc_GMTm6 ","<+06>-6"},
        {"TZ_Etc_GMTm7 ","<+07>-7"},
        {"TZ_Etc_GMTm8 ","<+08>-8"},
        {"TZ_Etc_GMTm9 ","<+09>-9"},
        {"TZ_Etc_GMTm10 ","<+10>-10"},
        {"TZ_Etc_GMTm11 ","<+11>-11"},
        {"TZ_Etc_GMTm12 ","<+12>-12"},
        {"TZ_Etc_GMTm13 ","<+13>-13"},
        {"TZ_Etc_GMTm14 ","<+14>-14"},
        {"TZ_Etc_GMT0 ","GMT0"},
        {"TZ_Etc_GMTp0 ","GMT0"},
        {"TZ_Etc_GMTp1 ","<-01>1"},
        {"TZ_Etc_GMTp2 ","<-02>2"},
        {"TZ_Etc_GMTp3 ","<-03>3"},
        {"TZ_Etc_GMTp4 ","<-04>4"},
        {"TZ_Etc_GMTp5 ","<-05>5"},
        {"TZ_Etc_GMTp6 ","<-06>6"},
        {"TZ_Etc_GMTp7 ","<-07>7"},
        {"TZ_Etc_GMTp8 ","<-08>8"},
        {"TZ_Etc_GMTp9 ","<-09>9"},
        {"TZ_Etc_GMTp10 ","<-10>10"},
        {"TZ_Etc_GMTp11 ","<-11>11"},
        {"TZ_Etc_GMTp12 ","<-12>12"},
        {"TZ_Etc_UCT ","UTC0"},
        {"TZ_Etc_UTC ","UTC0"},
        {"TZ_Etc_Greenwich ","GMT0"},
        {"TZ_Etc_Universal ","UTC0"},
        {"TZ_Etc_Zulu ","UTC0"},
        {"EOF", "eof"}
        };

        char *getTimeZoneLit(int tzindex) {
          return(tz[tzindex].tzlit);
        }
        char *getTimeZone(int tzindex) {
          return(tz[tzindex].tzzone);
        }

        #endif // TZDB_H
        #endif
```


body:
I am trying to move a `stepper motor` when a specific command is send to `Arduino Mega 2560`. This command is read character by character and stored in a `string variable`. Whenever a new command is sent, an act should be performed. However, it is not happening and I believe that the problem is in reading the sent command. I tried clearing the character and string variables, but to no avail. The sketch should run a loop that moves the motor `clockwise` or `counterclockwise` according to the command sent, which can be `"crx*"` for clockwise or `"clx*"` for anticlockwise, where `"*"` is the reading stop criterion of the characters.
Any suggestions what to do?
The script:

```
void(* resetFunc) (void) = 0;//Reset turn

// Stepper Motor X
const int stepPinX = 2; //X.STEP
const int dirPinX = 5; // X.DIR
const int pinEnable = 8;

// String read
char c;
String readString; //main captured String

// Unit steps
double av_len = 1.029; //medium length
double interval;
int cnt_steps = 0;
const int num_d = 200;//parameterized step
int fact = int(num_d / av_len);
int unit_len = fact * 1;//unit length (1mm)

void setup()
{
  // Sets pins as Outputs
  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);
  pinMode(pinEnable, OUTPUT);

  digitalWrite(pinEnable, HIGH);//lock driver on cnc shield

  Serial.begin(115200);
  Serial.setTimeout(1);

  while (1) {

    while ( (Serial.available() == 0) )
    {

    }

    if (Serial.available())  {
      c = Serial.read();  //gets one byte from serial buffer
      //Serial.println(readString);
      if (c == '*') {
        Serial.println(readString);//test response
        if (readString == "crx") {
          cnt_steps = cnt_steps + 1;
          Serial.println(cnt_steps);
          digitalWrite(pinEnable, LOW);
          digitalWrite(dirPinX, HIGH);
          for (int x = 0; x < unit_len; x++) {
            digitalWrite(stepPinX, HIGH);
            delayMicroseconds(500);
            digitalWrite(stepPinX, LOW);
            delayMicroseconds(500);
          }

        }
        else if (readString == "clx") {
          cnt_steps += -1;
          Serial.println(cnt_steps);
          digitalWrite(pinEnable, LOW);
          digitalWrite(dirPinX, LOW);
          for (int x = 0; x < unit_len; x++) {
            digitalWrite(stepPinX, HIGH);
            delayMicroseconds(500);
            digitalWrite(stepPinX, LOW);
            delayMicroseconds(500);
          }
        }
         digitalWrite(pinEnable, HIGH);//lock driver on cnc shield
         c = (char)0;
         Serial.flush();
         readString = "";
         //resetFunc();
      }

      else {
        readString += c; //makes the string readString

      }
    }
  }
}

void loop() {

}
```

title: Problem cleaning string read from serial buffer

Answers: 2

body:
When sending text commands to an Arduino, it is common to define a
“line-oriented protocol”: each command is transmitted as a single line,
with the line ending signifying the end of the command. Common line
endings are carriage return (CR = `'\r'` = `0x0d` = 13), line feed (LF =
`'\n'` = `0x0a` = 10) and the sequence CR+LF.

The Arduino serial monitor is designed to support this convention by
automatically appending a line ending when you press “Send”. This line
ending can be configured to one of the following options:
 - No line ending
 - Newline (meaning “line feed”)
 - Carriage return
 - Both NL & CR (but CR is actually sent before LF)

In your case, you have chosen to use `'*'` as a command termination
character. For this to work, you have to choose “No line ending” and add
the “\*” explicitly to the command. Alternatively, you may consider
changing your sketch so that it expects `'\r'` or `'\n'`, which is a
more standard way of ending a command.

body:
In addition to the good responses you have already received, I offer this.

For the Arduino, know the differences between String string and char arrays - there is much on this e.g., https://forum.arduino.cc/t/string-vs-string-vs-char-arrays-correct-approach/537468 . Many do not want to deal with the vagaries of String, but their use can be convenient.

Run this code:

    String readstring = "xxx";

    void setup() {
      Serial.begin(115200);
    }

    void loop() {
      if (Serial.available()) {
        readstring = Serial.readStringUntil('/n');
        Serial.print(readstring);
        Serial.println(" received");
        if (readstring.equals("crx")) {
          // move counter clockwise
          Serial.println("moving counter clockwise");
          // counterclockwise() <-- your function
        }
        else if (readstring.equals("clx") ) {
          // move clockwise
          Serial.println("moving clockwise");
          // clockwise() <-- your function
        }
        else {
          // bad command
          Serial.println("Bad command received - no action");
          // badcommand() <-- your function
        }
      }
    }

If you add functions for the stepper, it may do what you want within a limited context and with using the Arduino serial monitor for input. Take a look at the output.

[![enter image description here][1]][1]

Note that the serial monitor is set to "no line ending". The terminating character '/n' is provide by your input in the serial monitor. It will do what you want, but again, many advise you stay away from String.

  [1]: https://i.stack.imgur.com/Ya3u0.jpg


body:
I have been trying to use dual SPI masters, I know it is possible and followed the explanation best I could, and the code below is what I got. The issue is that the code is running the radio but not the LCD and if I want to run the LCD I tried using `SPI.being(14, 12, 13, 15)` which works to get LCD switching Black and White but then the radio stops working. Any help would be greatly appreciated.

    #include <SPI.h>

    # define HSPI_SS 15
    # define VSPI_SS 5

    //uninitalised pointers to SPI objects
    SPIClass * vspi = NULL;
    SPIClass * hspi = NULL;

    #include <RF24.h>
    #include <nRF24L01.h>

    RF24 radio(4, 5);   // CE, CSN
    const byte address[6] = "00001";     //Byte of array representing the address. This is the address where we will send the data. This should be same on the receiving side.
    boolean ButtonState = 0;

    // Adafruit 1.44" TFT breakout -> https://www.adafruit.com/product/2088
    #include <Adafruit_GFX.h> // Core graphics library
    #include <Adafruit_ST7735.h> // Hardware-specific library for ST7735

    // For 1.44" TFT with ST7735 use:
    Adafruit_ST7735 tft = Adafruit_ST7735(15, 2, 26); // (CS, DC, RST)

    //==================================================================================================================================================================================
    void setup() {
      Serial.begin(115200);

      //initialise two instances of the SPIClass attached to VSPI and HSPI respectively
      vspi = new SPIClass(VSPI);
      hspi = new SPIClass(HSPI);

      vspi->begin();
      hspi->begin();

      //set up slave select pins as outputs as the Arduino API
      pinMode(VSPI_SS, OUTPUT); //VSPI SS
      pinMode(HSPI_SS, OUTPUT); //HSPI SS

      radio.begin();                    //Starting the Wireless communication
      radio.openWritingPipe(address);   //Setting the address where we will send the data
      radio.setPALevel(RF24_PA_MIN);    //You can set it as minimum or maximum depending on the distance between the transmitter and receiver.
      radio.stopListening();            //This sets the module as transmitter

      // Use this initializer if using a 1.44" TFT:
      tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
      tft.setSPISpeed(1000000); // 1 MHz (has no effect on SCK)
    }

    //==================================================================================================================================================================================
    void loop() {

      ButtonState = 1;
      radio.write(&ButtonState, 1);    //Sending the message to receiver in, LOW);

      tft.fillScreen(ST77XX_BLACK);
      tft.fillScreen(ST77XX_WHITE);
    }

title: ESP32 Multiple Master SPI Setup -> VSPI - NRF24 and HSPI - ST7735 Simultaneously

Answers: 0


body:
My goal is to play sounds with my Arduino Nano Every. I tried the example sketch that comes with the library but I get the error:
```
**WARNING: library TMRpcm-master claims to run on avr architecture(s) and may be incompatible with your current board which runs on megaavr architecture(s).**
```

Is there such a big difference between the Nano and Nano every?

title: TMRpcm not compatible incompatible with current board

Answers: 1

body: I opened a issue on GitHub and the result is: tmrpcm only runs on avr architecture so it is incompatible with megaavr architecture(s).


body: How can you make ESP32 forget all the Wi-Fi networks it was connected to? Or at least forget the one to which the board is currently connected?

title: Forget WiFi ESP32

Answers: 0


body:
I'd like to wake up an ESP32 (on battery) when a pin changes from low to high, send a message via Bluetooth, and go to deep sleep again.

What Bluetooth mode should I use:

* Broadcast mode?
* Bluetooth Low Energy?
* iBeacon mode?
* another one?

If I'm correct, the following way would require pairing which is not possible in my case because my ESP32 will wake up and go to sleep often, hundreds of times per day (so I cannot pair manually each time):

```
#include <BluetoothSerial.h>
BluetoothSerial SerialBT;
byte BTData;
void setup()
{
  Serial.begin(115200);
  SerialBT.begin();
  Serial.println("BT starting, ready to pair");
}
void loop()
{
  if(SerialBT.available())
  {
    BTData = SerialBT.read();
    // do something with it, but in my case I don't need to read anything
  }
}
```

title: Which Bluetooth mode to use to wake up, send a message (to any listener) and go to deep sleep?

Answers: 0


body:
I have a sim800l module connected to the Rpi pico hardware UART

```
/*
SIM800       RPi Pico
5v           *External 2A 5v supply*
GND          GND
VDD          3v3
TXD          GP1
RXD          GP0
*/

void setup()
{
  Serial.begin(115200);

  while (!Serial)
    ;

  Serial1.begin(9600);

  Serial.print("Initializing");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.print(".");
  delay(1000);
  Serial.println(".");

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial1.println("AT"); //Once the handshake test is successful, it will back to OK
  updateSerial();
  delay(3000);

  Serial1.println("ATI"); //Returns the module name and revision.
  updateSerial();
  delay(3000);

  Serial1.println("AT+CCID"); //Read SIM information to confirm whether the SIM is plugged
  updateSerial();
  delay(3000);

  Serial1.println("AT+COPS?"); //Checks which network you are connected to
  updateSerial();
  delay(3000);

  Serial1.println("AT+COPS=?"); //Returns the list of operators present in the network.
  updateSerial();
  delay(3000);

}

void loop()
{
  updateSerial();
}

void updateSerial()
{
  delay(200);
  while (Serial.available())
  {
    Serial1.write(Serial.read());//Forward what Serial received to Software Serial Port
  }
  while (Serial1.available())
  {
    Serial.write(Serial1.read());//Forward what Software Serial received to Serial Port
  }

}
```

terminal response
```
AT
OK
ATI
SIM800 R14.18

OK
AT+CCID
XXXXXXXXXXXXXXXXXXXX
AT+COPS?
+COPS: 0,0,"Vodaa TelAT+COPS=?
+COPS: (2,"Vodaa Telecom","Ver
```

From what i know so far the SIM800L always ends its response with an "OK" but there are some commands that are cut short and not end with OK.  such as AT+CDID and AT+COPS. I do not know if the problem is with the pico or with sim800l. The sim800l seems to be working fine so i suspect its with the pico but if so, it might be a problem with the internal libraries which is beyond me.  To supoort that theory the number of characters that is being cut is about 20 characters, so it might be a setting i have to adjust

title: Reply from the SIM800l module is being cut short

Answers: 1

body:
Took me quite a while, but upon reading the pico's [documentation][1]

> The size of the receive FIFO may also be adjusted from the default 32
> bytes by using the setFIFOSize call prior to calling begin()
>
>     Serial1.setFIFOSize(128);
>     Serial1.begin(baud);

settinng it to a much higher value like 256 solves the problem

  [1]: https://arduino-pico.readthedocs.io/en/latest/serial.html


body:
I'm using an ESP8266 with deep sleep + wake up when `RST` pin goes low.

```
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
WiFiClient client;
HTTPClient http;
RTC_DATA_ATTR int bootcount = 0;

void setup() {
    bootcount ++;
    WiFi.begin("MySSID", "password");
    while (WiFi.status() != WL_CONNECTED) {
        delay(20);
    }
    // here I send "bootcount" with HTTP request
    ESP.deepSleep(0);
}
void loop() {
}
```

Here `RTC_DATA_ATTR int bootcount = 0;` fails with `RTC_DATA_ATTR` unknown.

**How to get the number of times the ESP8266 has woke up from deep sleep?**

title: ESP8266 RTC memory (for bootcount)

Answers: 1

body:
The ESP8266 RTC has 512 bytes of RAM that persist across restarts but not during power outages. While this RAM isn't persistent across power outages it also doesn't have the write limitations that flash memory has, making it appropriate for frequent writes which don't need to survive power loss.

The ESP32's compiler and software framework make it easy to access similar memory on it using the `RTC_DATA_ATTR` attribute; unfortunately as you found and @Juraj pointed out, the ESP8266's doesn't.

Thankfully the Arduino core for the ESP8266 includes support for reading and writing this area of memory using methods in the `ESP` object.

`ESP.rtcUserMemoryRead()` reads RTC memory and `ESP.rtcUserMemoryWrite()` writes RTC memory. In your case you could do something like this:
```
void setup() {
  uint32_t bootcount;

  if(!ESP.rtcUserMemoryRead(0, &bootcount, sizeof(bootcount))) {
    Serial.println("RTC read failed!");
    while(1)
      yield();
  }

  bootcount++;

  if(!ESP.rtcUserMemoryWrite(0, &bootcount, sizeof(bootcount))) {
    Serial.println("RTC write failed!");
    while(1)
      yield();
  }

  Serial.begin(115200);
  Serial.print("boot count is ");
  Serial.println(bootcount);
}

void loop() {
}
```

Not quite as convenient as the `RTC_DATA_ATTR` attribute but it still gets the job done.

I changed the type of `bootcount` from your example to `uint32_t` because it should never be negative, and the size of `uint32_t` is independent of the size of `int`.

Because the Arduino core is open source, you can [read the implementation of these functions][1] if you want to know how they work.

  [1]: https://github.com/esp8266/Arduino/blob/24c41524dc56c683d8926671bdd639d7411f2815/cores/esp8266/Esp.cpp#L141


body:
In Arduino IDE, I get this error "Error resolving FQBN: getting", when compiling a sketch. Can anyone help me get around this problem?

I am using the Arduino IDE. I have installed the M5Stack official 2.0.5-1.0 boards in Board Manager and the STAMP-PICO 0.0.2 library in Library Manager.

I get the following Compile error with ALL sketches, even the STAMP-PICO Basics IO example sketch.

"Error resolving FQBN: getting Error compiling for board STAMP-PICO."

Strangely ... in Arduino IDE v2.0.3, on the same computer using the same libraries and boards, the sketch compiles ok.

Sounds like something specific to Arduino IDE v1

title: Error resolving FQBN (Fully Qualified Board Name)

Answers: 1

body:
OK - I resolved the issue, myself.

The Boards Manager installations became confused, probably because I was using both Arduino 1.8.19 and Arduino IDE 2.0.3 on the same computer.

Somehow, the folder ~/Library/Arduino15/packages/m5stack/hardware/esp32/ contained more than one version of the esp32 board libraries, v2.0.5 as well as v2.0.5-1.0 and c2.0.5+1.0.

My fix involved uninstalling the M5 esp32 board library altogether and making sure that all sub-folder versions had been deleted too. Then, reinstalling the latest board version and restarting the Arduino IDE app.


body:
So I have created a method to read and return Ultrasonic Sensor Data. I have 2 Ultrasonic Sensors.

Below is my code.

    // Ultrasonic Pins
    #define T1 2
    #define E2 4
    #define E1 3
    #define T2 5
    // Motor Pins
    #define M1 7
    #define M2 8
    #define M3 9
    #define M4 10
    // Motor Movements Definition
    enum MOTOR
    {
        FORWARD,
        BACKWARD,
        LEFT,
        RIGHT,
        STOP
    };

    long duration1, distance1, duration2, distance2;

    void setup()
    {
        Serial.begin(9600);
        pinMode(E1, INPUT);
        pinMode(E2, INPUT);
        pinMode(T1, OUTPUT);
        pinMode(T2, OUTPUT);
        pinMode(M1, OUTPUT);
        pinMode(M2, OUTPUT);
        pinMode(M3, OUTPUT);
        pinMode(M4, OUTPUT);
        Motor(STOP);
    }

    void loop()
    {

        // If Both Sensors detect object then go in backward Direction
        while (DetectObject(T1,E1,1) < 10 && DetectObject(T2,E2,2) < 10)
        {
            Serial.println("Backward");
            Motor(BACKWARD);
            delay(200);
            Motor(STOP);
            delay(50);
        }
        // If Left Sensor detect object then go in Right Direction
        while (DetectObject(T1,E1,1) < 10 && DetectObject(T2,E2,2) > 10)
        {
            Serial.println("Right");
            Motor(RIGHT);
            delay(200);
            Motor(STOP);
            delay(50);
        }
        // If Right Sensor detect object then go in Left Direction
        while (DetectObject(T1,E1,1) > 10 && DetectObject(T2,E2,2) < 10)
        {
            Serial.println("Left");
            Motor(LEFT);
            delay(200);
            Motor(STOP);
            delay(50);
        }
        // If Both Sensors detect no object then go in Forward Direction
        while (DetectObject(T1,E1,1) > 10 && DetectObject(T2,E2,2) > 10)
        {
            Serial.println("Forward");
            Motor(FORWARD);
            delay(200);
            Motor(STOP);
            delay(50);
        }
    }

    void Motor(MOTOR motor)
    {
        switch (motor)
        {
        case STOP:
            digitalWrite(M1, LOW);
            digitalWrite(M2, LOW);
            digitalWrite(M3, LOW);
            digitalWrite(M4, LOW);
            break;
        case FORWARD:
            digitalWrite(M1, HIGH);
            digitalWrite(M2, LOW);
            digitalWrite(M3, HIGH);
            digitalWrite(M4, LOW);
            break;
        case BACKWARD:
            digitalWrite(M1, LOW);
            digitalWrite(M2, HIGH);
            digitalWrite(M3, LOW);
            digitalWrite(M4, HIGH);
            break;
        case LEFT:
            digitalWrite(M1, HIGH);
            digitalWrite(M2, LOW);
            digitalWrite(M3, LOW);
            digitalWrite(M4, HIGH);
            break;
        case RIGHT:
            digitalWrite(M1, LOW);
            digitalWrite(M2, HIGH);
            digitalWrite(M3, HIGH);
            digitalWrite(M4, LOW);
            break;
        default:
            break;
        }
        delay(100);
    }

    long DetectObject(uint8_t trigPin, uint8_t echoPin, int sensorNo)
    {
        digitalWrite(trigPin, LOW);
        delayMicroseconds(2);
        digitalWrite(trigPin, HIGH);
        delayMicroseconds(10);
        digitalWrite(trigPin, LOW);
        Serial.print("Distance Sensor");
        Serial.print(sensorNo);
        Serial.print(": ");
        Serial.print(pulseIn(echoPin, HIGH) * 0.034 / 2);
        Serial.println(" cm");
        return pulseIn(echoPin, HIGH) * 0.034 / 2;
    }

I am getting continuously getting ```Backward``` in the Serial monitor.

Output of Serial Monitor -

```
Distance Sensor1: 20 cm
Distance Sensor2: 15 cm
Backward
Distance Sensor1: 17 cm
Distance Sensor2: 21 cm
Backward
Distance Sensor1: 24 cm
Distance Sensor2: 9 cm
Backward
```

But when I created 2 different methods for each Ultrasonic Sensor. It is working fine.

I want to have a single method for N number of Ultrasonic Sensors.

Thanks in Advance!

title: Single Method for 2 Ultrasonic Sensor is not working as expected

Answers: 1

body:
The problem lies in the function, that does the ultrasonic detection. First I would suggest to not do Serial printing between the trigger pulse and `pulseIn()`, since the Serial transmission might take longer (for example when the buffer is full) and then your reading is garbage. Execute `pulseIn()` directly after the trigger pulse part and save the result in a local variable, which you can later print and return. If you do that, your problem is also solved.

For understanding what actually happens with your code, I annotated the function with some comments:

    long DetectObject(uint8_t trigPin, uint8_t echoPin, int sensorNo)
        {
            // Create Trigger pulse
            digitalWrite(trigPin, LOW);
            delayMicroseconds(2);
            digitalWrite(trigPin, HIGH);
            delayMicroseconds(10);
            digitalWrite(trigPin, LOW);

            // Do some printing
            Serial.print("Distance Sensor");
            Serial.print(sensorNo);
            Serial.print(": ");

            // Read a pulse and print it directly to Serial
            Serial.print(pulseIn(echoPin, HIGH) * 0.034 / 2);
            Serial.println(" cm");

            // Read ANOTHER pulse and return it
            return pulseIn(echoPin, HIGH) * 0.034 / 2;
        }

As you can see, you are trying to read 2 pulses. But there is only one echo pulse. That one pulse is read by the first execution of `pulseIn()` and you print the result to Serial, so in the Serial Monitor you are seeing the correct value.

After that you are executing `pulseIn()` again and returning the result. `pulseIn()` will wait for a pulse to begin (so it can start counting the time). But there is no second pulse on the echo line, so `pulseIn()` will exit after a timeout (by default 1s). On timeout this function returns zero. So every time you execute this function, it will return zero.

If you then look at the logic in `loop()`, you can easily see why you are only getting backwards. The code is stuck in the first while loop, because the value returned from the function is always zero, which is smaller than 10.

Here is a pseudo code version of how your function really should work:

    execute trigger pulse
    execute pulseIn function and save result in local variable
    print whatever you want to Serial
    return the value of the local variable


body:
PID library is available(built in) in standard installation  of arduino IDE or do we have to download it additionaly after installing our IDE?

How can i check which of libraries are available in my standard installation?

title: Confusion regarding PID library?

Answers: 1

body:
Open the Library Manager and search for the library you want. You will
see a list of libraries matching your query. Under the name of each of
those libraries, you will see a line showing the author and the version
number.

- if this lines stats with “Built-in”, then it is a library that comes
  with the standard installation of the IDE

- if the line ends with “INSTALLED”, then this library is installed in
  your system.


body:
 - i want to control this **12v** motor via arduino:

[![enter image description here][1]][1]

Power source is 12v 5A

motor will work 5 seconds in every 5 minutes and will be activated throught arduino mega

i will try to use **bd679a darlington transistor**:

 - Collector - Base Voltage (Vcbo) 80 V
 - Collector - Emitter Voltage (Vceo) 80 V
 - Collector Current (Ic) 4 A
 - Power Dissipation (Pd) [Tcase≤25°C] 40 W
 - Transition Frequency (fТ) 10 MHz
 - Min. DC current gain (β) 750
 - Integrated diode Yes
Case TO-126
Package type -14h

**Do i need to add diode(and will that drop voltage ) ?**

**also do i need any ressistors and why?**

[![enter image description here][2]][2]

  [1]: https://i.stack.imgur.com/HWJe4.jpg
  [2]: https://i.stack.imgur.com/P78fm.png

title: control 12v motor with NPN transistor via arduino

Answers: 1

body:
You are missing 2 things:

- You should add a resistor between the Arduino digital IO pin and the base of the transistor. Bipolar transistors are current amplifiers. Normally for driving motors with a microcontroller you want the transistor to operate in saturation anyway, so there is no need to fine tune the resistor. It is there for protecting the output pin of the Arduino from over current. The calculation is easy: Resistance is voltage divided by current `R = U / I`. The voltage is 5V for an Arduino Mega (output voltage of the digital IO pins is equal to the operating voltage of the Mega, thus 5V). The current here is the max current, that the output pin can withstand (you find such information in the datasheet of the microcontroller). It is 20mA for continuous load.

    So `R = 5V / 20mA = 250 Ohm`. Thus you need a resistor with at least 250 Ohm. 330 Ohm is normally readily available, so often people use one of these.

    You also asked about how many wants it should withstand. This is also easy to calculate: Power (in Watts) is voltage multiplied by current. So `P = U * I = 5V * 20mA = 0.1W`. So in this configuration the resistor will not ever need to withstand more than 0.1W. So 1/4W is enough.

- When driving motors you should include a flyback diode. This is a diode in reverse direction connected across the terminals of the motor. A motor is an inductive load (since it basically consists of some coils and magnets). Driving it with a varying voltage (like you need for controlling the motors speed or just to start and stop the motor) will induce reverse voltage spikes. These might damage your transistor and/or the Arduino. With the flyback diode connnected these voltage spikes can safely dissipate through that diode and not causing any harm.

So the circuit looks like this:

<!-- Begin schematic: In order to preserve an editable schematic, please
     don't edit this section directly.
     Click the "edit" link below the image in the preview instead. -->

![schematic](https://i.stack.imgur.com/oDTSj.png)

<!-- End schematic -->


body:
i need help on how to use busy pin in df player to arduino.... while playing one sound or df player is busy, i don't want to trigger df player by ultrasound sensors to play another song. here is my code without busy pin use in df player

```lang-cpp
#include "Arduino.h"
#include "SoftwareSerial.h"

#include "DFRobotDFPlayerMini.h"

const byte SENSOR_COUNT = 5;
byte triggerPins[SENSOR_COUNT] = {2,4,6,8,10};
byte echoPins[SENSOR_COUNT]    = {3,5,7,9,11};

SoftwareSerial mySoftwareSerial(12, 13); // RX, TX

DFRobotDFPlayerMini myDFPlayer;

void printDetail(uint8_t type, int value);

void setup()
{
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);

  for( byte i=0; i<SENSOR_COUNT; i++ )
  {
    pinMode(triggerPins[i], OUTPUT);
    pinMode(echoPins[i], INPUT);
  }

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.volume(10);  //Set volume value. From 0 to 30

}

int currentSound = -1;
void loop()
{

  for( byte i=0; i<SENSOR_COUNT; i++ ) // loop through all distance sensors
  {
    if( detectPresence(i) ) // check if there is an object near it
    {
      if(currentSound!=i) // check that it's a different sensor than the one that was last triggered
      {
        Serial.print("play song number ");
        Serial.println(i);
        myDFPlayer.play(i+1); // play song nr `i+1`
      }
      currentSound = i;
    }
  }

  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }

}

// detectPresence will return TRUE if there is an object close to it.
bool detectPresence(byte sensorNr)
{
  if( sensorNr>=SENSOR_COUNT )
    return false;
  long duration, distance;
  //digitalWrite(triggerPins[sensorNr], LOW);  // Added this line
  //delayMicroseconds(10); // Added this line
  digitalWrite(triggerPins[sensorNr], HIGH);
  delayMicroseconds(15); // Added this line
  digitalWrite(triggerPins[sensorNr], LOW);
  duration = pulseIn(echoPins[sensorNr], HIGH);
  distance = duration/58;

  return distance<30;// choose your own value here, from which distance it should trigger a sound
}

void printDetail(uint8_t type, int value){

  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}
```

Answers: 1

body:
The busy pin is just a pin, that gets driven LOW, when a song is playing, and HIGH when nothing is playing. So connect it to a free digital IO pin on your Arduino and set that pin to input with:

    pinMode(busy_pin, INPUT);

(Note: You yourself need to define `busy_pin`, since I don't know where you will connect it). Then just read this pin in the if statement together with `detectPresence(i)`:

    if(!digitalRead(busy_pin) && detectPresence(i))

The `!` is to make the expression true, when `digitalRead(busy_pin)` returns 0 (LOW). This way the code will not even check for presence, when there is currently a song playing.


body:
I want to make a project with a (Nokia 5110) display using u8g2 library.
Here I have the code for my program:

```lang-cpp
#include <Arduino.h>
#include <U8g2lib.h>
#include <TM1637Display.h>
#include <EEPROM.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#define LED_PIN 5
#define BUTTON_PIN 6
#define BUZZ_PIN 7
#define BUTTON_L 2
#define BUTTON_R 3
#define BUTTON_START 4

//48x84 disp.
U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R2, 13, 11, 10, 12, 8); //rotate, clk, DIN, CE, DC, RST //

byte lastButtonState = 0;
byte ledState;
float cpu_gauge = 0.0;
char buffer[40];
int move = 7;
float cpu_gauge_step = 0.5;
byte eeprom_led;

void set_led(){
  if( digitalRead(LED_PIN) == 1 ) ledState = 1;
      if( digitalRead(LED_PIN) == 0 ) ledState = 0;}

void backlight(){
byte buttonState = digitalRead(BUTTON_PIN);  //monitor button state
  if (buttonState != lastButtonState) {  //check if not equal
    lastButtonState = buttonState;       //if prev. true, make equal
      if (buttonState == HIGH) {
        ledState = (ledState == HIGH) ? LOW : HIGH;
          digitalWrite(LED_PIN, ledState);    }}}

void status_bar(){
  if (cpu_gauge > cpu_gauge_step*1) u8g2.drawBox(2,13,6,8); //x, y , size in x, size in y
    if (cpu_gauge > cpu_gauge_step*2) u8g2.drawBox(2 + 1*move,13,6,8);
      if (cpu_gauge > cpu_gauge_step*3) u8g2.drawBox(2 + 2*move,13,6,8);
        if (cpu_gauge > cpu_gauge_step*4) u8g2.drawBox(2 + 3*move,13,6,8);
          if (cpu_gauge > cpu_gauge_step*5) u8g2.drawBox(2 + 4*move,13,6,8);
            if (cpu_gauge > cpu_gauge_step*6) u8g2.drawBox(2 + 5*move,13,6,8);
              if (cpu_gauge > cpu_gauge_step*7) u8g2.drawBox(2 + 6*move,13,6,8);
                if (cpu_gauge > cpu_gauge_step*8) u8g2.drawBox(2 + 7*move,13,6,8);
                  if (cpu_gauge > cpu_gauge_step*9) u8g2.drawBox(2 + 8*move,13,6,8);
                    if (cpu_gauge >= cpu_gauge_step*10) u8g2.drawBox(2 + 9*move,13,6,8);
}

void setup(void) {
  pinMode(LED_PIN, OUTPUT);
    pinMode(BUTTON_PIN, INPUT);
      pinMode(BUZZ_PIN, OUTPUT);
       pinMode(BUTTON_L, INPUT);
        pinMode(BUTTON_R, INPUT);
          pinMode(A7, INPUT);
            pinMode(BUTTON_START, INPUT);
              eeprom_led = EEPROM.read(0);
                digitalWrite(LED_PIN, eeprom_led);
                  set_led(); //sets the led state to 1 or 0 depending on digital write
            Serial.begin(9600);
            u8g2.begin();

}

void loop(void) {

    EEPROM.update(0,ledState);
    /*pomiar = EEPROM[ 0 ];
    delay(2500);//
    Serial.println(pomiar);//
    Serial.println(cpu_gauge);
    int pomiar = digitalRead(BUTTON_START);
    Serial.println(pomiar);*/

  backlight();
  cpu_gauge = analogRead(A7) * (5.0/1022);

  u8g2.firstPage();
  do {
  u8g2.drawRFrame(0,12,74,10,3); //pos X,Y  length, width, corner
  status_bar();

  u8g2.setFont(u8g2_font_busdisplay8x5_tr);
    u8g2.setCursor(0,8);
      char pomiar_str[5];
        dtostrf(cpu_gauge,0,2, pomiar_str);
          sprintf(buffer, "LOAD: %sV", pomiar_str);
            u8g2.print(buffer);

  u8g2.setCursor(0,36);
    u8g2.print("bckgrnd_tsks:");
      u8g2.setCursor(48,48);
        sprintf(buffer, "led: %d", ledState);
          u8g2.print(buffer);
            u8g2.drawStr(0,48,"buzz:");

  if (cpu_gauge > 4.80){
    digitalWrite(7,1);
      u8g2.setCursor(0,48);
        u8g2.setFont(u8g2_font_busdisplay8x5_tr);
          u8g2.setFont(u8g2_font_open_iconic_play_1x_t);
          u8g2.drawGlyph(27, 48, 0x0040);}
  else
    digitalWrite(7,0);

  } while ( u8g2.nextPage() );}
```

I have succesfully made a program, that:

-Has a pushbutton, to turn off, and on the backlight with each press
-Writes to the EEPROM the state of the LED, and reads it at startup
-Displays an analogRead value, from the potentiometer and also displays a progress bar of the given value
-Displays the state of the backlight
-Turns on the buzzer, if the analogRead value exceedes some value
-Displays an indicator, if the buzzer is turned on

Now, let's assume that what this program does, is called option "A", and A in this example works all the time, because there is nothing else.
I want to create a menu, that would have option A, B, C, D. Assume that formatting and pushbutton actions, doesn't matter for now.

A: Is what was described before.
B: Clock. Just display a clock.
C: Stopwatch.
D: Setting the time.

I see two ways of creating such menu.

1: Is to build a selectable/scrollable menu that would have labels, and by choosing, and pressing a button, we would enter desired function.
2: Ditch the selectable menu. One pushbutton will switch from option A to D. Something like a casio watch.

I'd prefer the second option, I think it'll be easier to do

What I don't understand, is the U8G2 reference manual.
I don't really understand the concept of the buffer, sendBuffer, userInterfaceSelectionList, and some more stuff, that I can't name for now.

My understanding is, that i have to make some array, of functions.
Like:
```
Array [] = {default_display();, clock();, stopwatch();, setting();)
```
And with a button, I'd go thru this array like so:
```
Array = 0;
 If (digitalRead(some_button_pin) == High){
  Array + 1;}
If (Array > 3){
 Array = 0;}
```
And in those funtions, it would have implemented options, like the backlight turned on, or something else, whatever,

Now I don't know if that makes any sense. If it's transferable into code.
I don't know if I need to clear the display, and how do I do that only once before entering the option. How do I make it, so that all the variables related to clock, the stopwatch still work even if I'm not displaying it. I'm honestly lost, and I just need guidance with this, becuase I have only had C for 1 semester at Electrical Engineering. I'm not a programist, but I really want to make it work, but it just isn't explained in the way like I don't know, pulldown resistors, where you can make some assumptions, and with them explain how something works. No, it looks like this:
```
void u8g2_SetBufferPtr(u8g2_t *u8g2, uint8_t *buf)
```
And yeah, I just don't know how do I go around it, how do I navigate in it. Thank you for any help.

title: I need help with creating a menu using u8g2 library

Answers: 1

body:
I have figured it out.
First thing that has to be said. If you're used to creating function definitions before the setup, you can't do that with u8g2 library. You can create function definitions after calling u8g2.begin in setup. Now there are two ways how you can do it, in the "Casio watch" fashion, but first create a varaible that will read how many times you've clicked, and store that somewhere, and add a condition, that will revert it to 1 after some amount of clicks.
1st way: Create a switch case, where the variable will be your switch, and in the cases (x to n) write what you want, graphics, text, whatever. Now the problem that I've had, is that when I've pasted the same code, and changed only some minor text, the whole thing glitched. It went through 1 and 2, normally, and then everything from case 3 and 4 was merged toghether, and case 4 was empty, and so was the screen. I couldn't fix it, so I came up with the second approach. Create as many IF conditions, as you have menu option. So it goes like this:
 If (menu_counter == 1){ //your input to the screen// }
And so for the rest. As far as I have tested this, it works, even if the code is the same for both IF statements. Now I'd have to implement the menu selection list on top. Leaving the answer to my own question, hopefully someone will find it useful.


body:
The project has a makeshift meter (via a half circle cutout and a servo motor operated lever). On program start (button 2), the lever will move to the left hand side at the 9 o'clock position. Once in place, after a short delay, the program will accept input from the button 1 and keep a count while moving the lever toward the 3 o’clock position stopping at at 10-2 w 2 sec delay. When it reaches the position, it stops the count and remembers it.

Repeat same thing but with buttons 4 and 5 respectively. Really important that the count is saved for both buttons 1 and 5.

Pressing button 3 will measure the inputs of button 5 and display them on the meter as a ratio of button 5 presses over button 1 + button 5 presses. If it leans right, that means you had more presses in the first stage than second (for ease of understanding I’ll probably have instructions that say to start with right hand so that leaning right means right hand dominance and left is left handed). Below is a picture of my set up.

*I numbered the buttons 1-5 left to right not by the pin number.

The problem I have is that after button 2 or 4 get pushed the servo just keeps moving to the seven positions I have set as a timer over and over.

    #include <Servo.h>

    const int button1 = 2;   // button 1 pin/left hand main pin
    const int button2 = 3;   // button 2 pin/left start pin
    const int button3 = 4;   // button 3 pin/right hand main pin
    const int button4 = 5;   // button 4 pin/right start pin
    const int button5 = 6;   // button 5 pin/results pin
    const int servoPin = 9;  // servo motor pin

    int count1 = 0;          // counter for button 1
    int count2 = 0;          // counter for button 5

    Servo servo;             // servo motor object

    void setup() {
      // set button pins as inputs
      pinMode(button1, INPUT);
      pinMode(button2, INPUT);
      pinMode(button3, INPUT);
      pinMode(button4, INPUT);
      pinMode(button5, INPUT);

      servo.attach(servoPin); // attach servo motor to pin
    }

    void loop() {
      if (digitalRead(button2) == HIGH) {  // if button 2 is pressed
        // move servo motor to 9 o'clock position
        servo.write(180);
        delay(500);  // wait for servo to reach position

        // start accepting input from button 1
        while (digitalRead(button1) == LOW) {
          count1++;  // increment counter
          // move servo motor to 3 o'clock position
          servo.write(180);
          delay(2000);  // wait for servo to reach position
          servo.write(150);
          delay(2000);  // wait for servo to reach position
          servo.write(120);
          delay(2000);  // wait for servo to reach position
          servo.write(90);
          delay(2000);  // wait for servo to reach position
          servo.write(60);
          delay(2000);  // wait for servo to reach position
          servo.write(30);
          delay(2000);  // wait for servo to reach position
          servo.write(0);
          delay(2000);  // wait for servo to reach position

        }

        // repeat the same process for button 4
        while (digitalRead(button4) == LOW) {
          count2++;  // increment counter
          // move servo motor to 3 o'clock position
          servo.write(180);
          delay(2000);  // wait for servo to reach position
          servo.write(150);
          delay(2000);  // wait for servo to reach position
          servo.write(120);
          delay(2000);  // wait for servo to reach position
          servo.write(90);
          delay(2000);  // wait for servo to reach position
          servo.write(60);
          delay(2000);  // wait for servo to reach position
          servo.write(30);
          delay(2000);  // wait for servo to reach position
          servo.write(0);
          delay(2000);  // wait for servo to reach position
        }
      }

      if (digitalRead(button3) == LOW) {  // if button 3 is pressed
        // calculate ratio of button 4 presses to total button presses
        float ratio = (float)count2 / (count1 + count2);

        // Display ratio on meter
        servo.write(90 + (int)(ratio * 90));
      }
    }

[![Arduino set up][1]][1]

  [1]: https://i.stack.imgur.com/eh4X9.png

title: How do I stop my servo from repeating the loop and perform the rest of the functions?

Answers: 1

body:
You have pulldown resistors on all your buttons, so all of your input pins are LOW when nobody is touching the buttons. When you press a button, the input goes HIGH. In your code, when you do

      if (digitalRead(button2) == HIGH) {  // if button 2 is pressed

it enters the if block, if the button is pressed, because the button2 input is high when the button is pressed. Then you move the servo to position 180 and wait a bit. The next line

        while (digitalRead(button1) == LOW) {

enters the while loop if the input pin is low. The input pin is that, when the button is NOT pressed, because of the pulldown resistor and that is why the servo starts moving when button2 is pressed, unless button1 is also pressed when you press button2. To stop that, change the LOW to HIGH in the while loop condition. Then it will only enter the while loop when the button is pressed and skip it if it is not pressed..

As suggested by the busybee, you might benefit from studying state machines.


body:
I have an ESP8266 project that requires setting the SSID and password for a network via an Access Point.  Everything works fine, the only issue is if you send incorrect credentials to the access point, the server returns an empty response before the timeout period elapses, and the error message is never sent to the client.

If the connection is successful then the success message is appropriately sent to the client.  It's almost like the `WiFi.begin()` function detects the connection fails on its own, and something there is preventing me from sending my own response.

```
%  curl -X POST "http://192.168.1.1/authenticate?ssid=FakeNetworkpassword=87654321"
curl: (52) Empty reply from server
```

Did some research and saw some mentions to keep the `loop` running, so I attempted to do so below, but to no avail.  Would appreciate any ideas, thanks.

```
#include "ESP8266WiFi.h"
#include "ESP8266HTTPClient.h"
#include "ESP8266WebServer.h"

HTTPClient http;
WiFiClient client;

ESP8266WebServer server(80);
IPAddress ipAP(192, 168, 1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

unsigned long previousMillisConnection = 0;
unsigned long startingMillisConnection = 0;
const unsigned long CONNECTION_PERIOD = 1000;
const unsigned long CONNECTION_TIMEOUT = 10000;

int DELAY = 40;

char ssid[64] = { 0 };
char password[64] = { 0 };

char ssidNew[64];
char passNew[64];

const int STATE_DEFAULT = 0;
const int STATE_CREDS = 1;
int state = STATE_DEFAULT;

void setup() {
  Serial.begin(9600);

  WiFi.softAPConfig(ipAP, gateway, subnet);
  WiFi.softAP("ESP8266", "12345678");
  delay(100);

  server.on("/authenticate", HTTP_POST, onSetCredentials);
  server.begin();

  performWifiConnect(ssid, password);
  WiFi.waitForConnectResult(CONNECTION_TIMEOUT);

  Serial.println("Initialization complete");
}

void loop() {
  if (state == STATE_DEFAULT) {
    server.handleClient();
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected!");
    }
  }

  else if (state == STATE_CREDS) {
    whileConnecting();
  }

  delay(DELAY);
}

void performWifiConnect(char ssid[], char password[]) {
  Serial.println("Attempting to connect to " + String(ssid) + "...");
  WiFi.setAutoReconnect(false);
  WiFi.persistent(false);
  WiFi.begin(ssid, password);
}

void onWifiConnected() {
  Serial.println("WiFi connected " + WiFi.localIP().toString());
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
}

void onSetCredentials() {
  Serial.println("onSetCredentials");

  server.arg("ssid").toCharArray(ssidNew, 64);
  server.arg("password").toCharArray(passNew, 64);

  if (String(ssidNew) == String(ssid) && WiFi.status() == WL_CONNECTED) {
    Serial.println("Already connected to " + String(ssidNew));
    server.send(200, "application/json", "{ \"success\": true, \"changed\": false }");
  } else {
    Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
    state = STATE_CREDS;
    performWifiConnect(ssidNew, passNew);
    startingMillisConnection = millis();
  }
}

void whileConnecting() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillisConnection >= CONNECTION_PERIOD) {
    previousMillisConnection = currentMillis;

    Serial.println("checking connection...");

    // Success
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected to " + String(ssidNew) + " successfully!");

      strcpy(ssid, ssidNew);
      strcpy(password, passNew);

      server.send(200, "application/json", "{ \"success\": true, \"changed\": true }");

      state = STATE_DEFAULT;
    }

    // Failure
    if (currentMillis - startingMillisConnection >= CONNECTION_TIMEOUT) {
      Serial.println("connection failed, attempting to reconnect to old network!");
      Serial.println("ssidOld: " + String(ssid));
      Serial.println("passOld: " + String(password));

      String errorMessage = "Timed out while attempting to connect to " + String(ssidNew);
      Serial.println(errorMessage);
      server.send(500, "application/json", "{\"errorMessage\":\"" + errorMessage + "\"}");

      performWifiConnect(ssid, password);

      WiFi.waitForConnectResult(CONNECTION_TIMEOUT);

      state = STATE_DEFAULT;

      if (WiFi.status() != WL_CONNECTED) {
        Serial.println("Could not return to old network!");
      }
    }
  }
}
```

title: Changing ESP8266 WiFi network via Access Point

Answers: 2

body:
I recommend you to use the WiFiManager library. It has the WiFi provisioning solved.

----------

To join an AP esp8266 must change the WiFi radio channel to the channel of the AP. Since the esp8266 has only one radio, the SoftAP must change the channel too. This causes the SoftAP clients to disconnect.

The solution is respond to the configuration request before connecting to AP, then let the configuration page do a new request for the result.

To illustrate here is a simple example:
```
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif

void setup() {

  Serial.begin(115200);
  delay(500);

#ifdef ESP32
//  WiFi.begin(); // use SSID and password stored by SDK. commented out to test the Configuration AP
#else
//  WiFi.disconnect(); // forget the persistent connection to test the Configuration AP
#endif

  // waiting for connection to remembered  Wifi network
  Serial.println("Waiting for connection to WiFi");
  WiFi.waitForConnectResult();

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println();
    Serial.println("Could not connect to WiFi. Starting configuration AP...");
    configAP();
  } else {
    Serial.println("WiFi connected");
  }
}

void loop() {
}

void configAP() {

  WiFiServer configWebServer(80);

  WiFi.mode(WIFI_AP_STA); // starts the default AP (factory default or setup as persistent)

  Serial.print("Connect your computer to the WiFi network ");
#ifdef ESP32
  Serial.print("to SSID of you ESP32"); // no getter for SoftAP SSID
#else
  Serial.print(WiFi.softAPSSID());
#endif
  Serial.println();
  IPAddress ip = WiFi.softAPIP();
  Serial.print("and enter http://");
  Serial.print(ip);
  Serial.println(" in a Web browser");

  configWebServer.begin();

  while (true) {

    WiFiClient client = configWebServer.available();
    if (client) {
      char line[64];
      int l = client.readBytesUntil('\n', line, sizeof(line));
      line[l] = 0;
      client.find((char*) "\r\n\r\n");
      if (strncmp_P(line, PSTR("POST"), strlen("POST")) == 0) {
        l = client.readBytes(line, sizeof(line));
        line[l] = 0;

        // parse the parameters sent by the html form
        const char* delims = "=&";
        strtok(line, delims);
        const char* ssid = strtok(NULL, delims);
        strtok(NULL, delims);
        const char* pass = strtok(NULL, delims);

        // send a response before attemting to connect to the WiFi network
        // because it will reset the SoftAP and disconnect the client station
        client.println(F("HTTP/1.1 200 OK"));
        client.println(F("Connection: close"));
        client.println(F("Refresh: 10")); // send a request after 10 seconds
        client.println();
        client.println(F("<html><body><h3>Configuration AP</h3><br>connecting...</body></html>"));
        client.stop();

        Serial.println();
        Serial.print("Attempting to connect to WPA SSID: ");
        Serial.println(ssid);
        WiFi.persistent(true);
        WiFi.setAutoConnect(true);
        WiFi.begin(ssid, pass);
        WiFi.waitForConnectResult();

        // configuration continues with the next request

      } else {

        client.println(F("HTTP/1.1 200 OK"));
        client.println(F("Connection: close"));
        client.println();
        client.println(F("<html><body><h3>Configuration AP</h3><br>"));

        int status = WiFi.status();
        if (status == WL_CONNECTED) {
          client.println(F("Connection successful. Ending AP."));
        } else {
          client.println(F("<form action='/' method='POST'>WiFi connection failed. Enter valid parameters, please.<br><br>"));
          client.println(F("SSID:<br><input type='text' name='i'><br>"));
          client.println(F("Password:<br><input type='password' name='p'><br><br>"));
          client.println(F("<input type='submit' value='Submit'></form>"));
        }
        client.println(F("</body></html>"));
        client.stop();

        if (status == WL_CONNECTED) {
          delay(1000); // to let the SDK finish the communication
          Serial.println("Connection successful. Ending AP.");
          configWebServer.stop();
          WiFi.mode(WIFI_STA);
          return;
        }
      }
    }
  }
}
```

body:
There are several intertwined issues in this one.

Firstly, `setup()` has some code running before it should be.

That first problem is here:
```
  server.on("/authenticate", HTTP_POST, onSetCredentials);
  server.begin();

  performWifiConnect(ssid, password);
  WiFi.waitForConnectResult(CONNECTION_TIMEOUT);
```
You've already set `ssid` and `password` to be null, and server.begin() won't run the server yet (I'll get to that issue in a minute), so this is setting your credentials to be null at the start of the program. There's no point in running `waitForConnectResult()` then, because there is nothing to connect. There may be logic in setting `performWifiConnect()` though, since if you've ever set the Wi-Fi credentials with `wifi.begin()` *before* turning off persistent, those credentials are still remembered (it just won't remember new ones).

The next issue is that you're only handling server requests while the connection *is not invalid*. Thus, when there is an invalid credential for the network, the server doesn't run, and you don't get a response.

```
void loop() {
  if (state == STATE_DEFAULT) {
    server.handleClient();
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected!");
    }
  }

  else if (state == STATE_CREDS) {
    whileConnecting();
  }

  delay(DELAY);
}
```
As you can see, `server.handleclient()` (the actual server; the ability to respond to requests) is only running while it does not have `state == STATE_DEFAULT`. *That* is then changed, `state = STATE_CREDS;`, during the callback for getting network credentials. You'll probably get a reply from the request handler that's currently running, but this will otherwise cause you problems since the server then never responds to any future requests. You **must** continually call `server.handleclient()` or nothing server-related will work.

But, something else is also wrong. You can only pass replies back from the server if you actually send them *while the server is still processing a request.*
```
else {
    Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
    state = STATE_CREDS;
    performWifiConnect(ssidNew, passNew);
    startingMillisConnection = millis();
  }
```
As you can see, there is no `server.send()` in this branch, so you'll get no reply. This is likely the most immediate cause of your problem with an empty response.

Instead, you have that in the function `whileConnecting()`. As noted earlier, the server cannot send replies that aren't in the function it calls when it gets a request, or in functions called by that function. The server does not call `whileConnecting()`, `loop()` does. So it can't see or send that reply.

(Side note: This requirement of the server is implemented pretty weirdly, since you're calling server methods while one of its methods calls your code, only for the server to then ask itself what you told it while it was busy with your request, grab that buffer, and return it to the client. But it **only** does that check somewhere inside `server.handleClient()`, and other `send()` calls will either be ignored or get queued to send the next time the client makes a request.)

If you were to wait for a connection inside the server's request handler instead, and then send the error/success messages there too, this might work. It's still bad practice since the server (that part I said you always want to **not** hold up) and the entire rest of your code will be on hold while it waits to connect, but you'll *probably* have it work **as long as there's nothing else time-critical or important going on**.

The best approach would be to have your client poll a second address (or just the same address with no POST values, then have the server check whether there are no args) and have that say whether it is currently connected.

On that note, your connection checking code also has a problem. `loop()` has a delay in it, which is already going to bog things down. But you also have the whileConnecting function check for elapsed time. This *is* the proper way to coordinate multiple independent check-back-and-do-stuff operations, so you're aware of it, but this hasn't been transferred to the rest of the code.

Except, **also** in whileConnecting, you then call `WiFi.waitForConnectResult(CONNECTION_TIMEOUT);`. This will **block** that function until a result is present, which thus halts everything else for however long that timeout is. The only place you "should" use this (again, probably bad practice) is inside the server if you were trying to have it directly reply with the connection status **or** if there's not anything else important going on (which there is, so this is an issue). Since you're already running code periodically on a timer, just have this code check for the timeout directly (easiest method: call the connect function with the credentials, set the check-back time by `timeout`, then check again), and just reconnect then instead of forcing a wait. This will leave the server and the rest of your code responsive.

Now, with all (well, most) of that put together:
(NOTE: This code will need some changes made to the rest of your code, and may require adjustment itself, but it should get you very close. I suggest making a backup copy of your code first in case you need to reference or fix something. I also wrote this in a text editor, as I don't currently have access to the IDE to test this. There might be minor errors.)

Solution A (have the server wait and tell you the results):
(NOTE: also, delete `whileConnecting()` and all the `state` if you use this method; you want to make sure server.handleClient() is always being called until the connection is actually successful, or just plain always.)
```
void onSetCredentials() {
  Serial.println("onSetCredentials");

  server.arg("ssid").toCharArray(ssidNew, 64);
  server.arg("password").toCharArray(passNew, 64);

  if (String(ssidNew) == String(ssid) && WiFi.status() == WL_CONNECTED) {
    Serial.println("Already connected to " + String(ssidNew));
    server.send(200, "application/json", "{ \"success\": true, \"changed\": false }");
  } else {
    Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
    performWifiConnect(ssidNew, passNew);
    startingMillisConnection = millis();
    //code to detect the server connection status and respond starts here//
    WiFi.waitForConnectResult(CONNECTION_TIMEOUT);
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("Connected to " + String(ssidNew) + " successfully!");

      strcpy(ssid, ssidNew);
      strcpy(password, passNew);

      server.send(200, "application/json", "{ \"success\": true, \"changed\": true }");
    }

    // Failure
    if (currentMillis - startingMillisConnection >= CONNECTION_TIMEOUT) {
      Serial.println("connection failed, attempting to reconnect to old network!");
      Serial.println("ssidOld: " + String(ssid));
      Serial.println("passOld: " + String(password));

      String errorMessage = "Timed out while attempting to connect to " + String(ssidNew);
      Serial.println(errorMessage);
      server.send(500, "application/json", "{\"errorMessage\":\"" + errorMessage + "\"}");
    }
  }
}
```
This solution (A) will *probably* give you the connection status back, assuming the Wi-Fi connection attempt times out before the cURL request/server does. I haven't actually tested this and I did mention it's kinda bad practice.

Solution B (Poll the server for connection status rather than waiting for a reply):
(Note: Again, delete any `state` logic and `whileConnecting()` from the other code.)
```
void onSetCredentials() {
  Serial.println("onSetCredentials");
  if (!server.hasArg("ssid")){ //check for no-arg request and return conn status//
    server.send("200", "text/plain", (WiFi.status() != WL_CONNECTED)? "Connected" : "Not Connected"); //or whatever other message(s) you want
    //You may also want to add some sort of Serial.print()-type logging here too, since I didn't.//
  }
  else{ //existing connection setup request handler resumes here//
    server.arg("ssid").toCharArray(ssidNew, 64);
    server.arg("password").toCharArray(passNew, 64);

    if (String(ssidNew) == String(ssid) && WiFi.status() == WL_CONNECTED) {
      Serial.println("Already connected to " + String(ssidNew));
    } else {
      Serial.println("Switching from " + String(ssid) + " to " + String(ssidNew));
      performWifiConnect(ssidNew, passNew);
      startingMillisConnection = millis();
    }
  }
}
```

With Solution B, you can call the cURL command to the ESP8266 *without* the `ssid` and `password` set, and you'll get a connection status back instead. This may take a few attempts while it's still in the process of connecting, but if it *remains* not connected, you know the credentials are wrong.


body: I am having an electrical conductivity sensor (Sensorex CS150 with three tinned wires Red, Black and white <https://sensorex.com/product/sensorex-cs150-12-mm-graphite-contacting-conductivity-sensor/> ). I want to measure EC of nutrient soultion used in aquaponics. I have searched on internet for connection setup and everywhere sensor (with BNC connector) is connected to arduino via expansion board. Do I require this type of expansion board or can I directly connect sensor to analog pin of arduino.

title: Can a three wire Electrical conductivity sensor (Sensorex CS 150) be used directly with arduino?

Answers: 2

body:
[Product Manual][1]

  [1]: https://sensorex.com/wp-content/uploads/2021/09/CS150-Instructions.pdf
Seem to be a simple conductivity measurement so applying a voltage direct from the Arduino via a suitable resistor and using an analog input to measure the voltage drop should work OK. You may need to experiment with the resistor value to get a good range of readings depending on the conductivity of the solution you are measuring

body:
EC electrodes is an active sensor that requires an excitation voltage to be applied to get the result. When A DC voltage is apply to the two conductors, it caused iron to be flow from one conductor to another, causing polarisation and chemical reaction. Therefore you can't use it directly with Arduino.

To measure EC you need a Wien bridge oscillator which is used to generate an alternative current(AC) waveform for the excitation of the EC electrode. In order to avoid polarization, an alternative current (AC) typically ranging from 1kHz to 20kHz is used to provide the exitation of the electrode. The AC current is read and converted back to a DC voltage as the measurement result.

You also need a precision amplifier in order to get a meaningful measurement.

The EC value is also subject to temperature changes, so it may also requires to measure the temperature of the liquid and adjust the result for temperature compensation.

I have an [product review article](https://www.e-tinkers.com/2020/07/a-review-on-seeed-studio-ph-and-ec-sensor-kits-part-2/) where it describe how EC measurement works and what is required (both hardware and software) to measure EC, you might want to further read to understand more.

Other reference:

[Conductive of a solution - Andy Connelly](https://andyjconnelly.wordpress.com/2017/07/14/conductivity-of-a-solution/).

[Conductivity Measurement Theory Guide - ](https://www.mt.com/us/en/home/library/guides/lab-analytical-instruments/Conductivity-Measurement-Theory-Guide.html).

[One-chip conductivity meter monitors salt concentration - Michael Ahmon Electronics/Sept 15, 1977](https://www.e-tinkers.com/wp-content/uploads/2020/07/one-chip_conductivity_meter_by_Michael_Ahmon_Sept_1977_Electronics.pdf).


body:
I'm getting this error by running a FreeRTOS program on my ESP32 using arduino ide, I don't understand why this happens because this same program works on an arduino Uno with no errors:
```
Guru Meditation Error: Core  0 panic'ed (Unhandled debug exception).
Debug exception reason: Stack canary watchpoint triggered (task1)
Core  0 register dump:
PC      : 0x40088a4f  PS      : 0x00060636  A0      : 0x800d3155  A1      : 0x3ffb9130
A2      : 0x3ffb8eb4  A3      : 0xffffffff  A4      : 0x00060620  A5      : 0x00060623
A6      : 0x00060623  A7      : 0x00000001  A8      : 0x00000001  A9      : 0x00000000
A10     : 0x00060623  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x00000000
A14     : 0x007bee88  A15     : 0x003fffff  SAR     : 0x00000000  EXCCAUSE: 0x00000001
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000
```

This is the code I'm using:

```
//#include <Arduino_FreeRTOS.h>
//Overload happens if xTaskGetTickCount – lastTickCount (the first parm to vTaskDelayUntil) is >= period in ticks

void task1(void *pvParameters);
void task2(void *pvParameters);
void task3(void *pvParameters);

void setup() {

  Serial.begin(115200);

  //Create tasks
//xTaskCreate(Task function, Task name, , Task parameter, Task priority, );
  Serial.println("111111");
  xTaskCreate(task1, "task1", 512, NULL, 1, NULL);
  Serial.println("222222");
  xTaskCreate(task2, "task2", 512, NULL, 2, NULL);
  xTaskCreate(task3, "task3", 512, NULL, 3, NULL);
  //vTaskStartScheduler();

}

void loop() {}

void task1(void *pvParameters) {

  (void) pvParameters;
  TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;

  waketime = xTaskGetTickCount();

  while(1){

    Serial.println('M'); //This happens almost immediately, so we need to add an artificial delay, a  to simulate a task running for a few ms, it only serves as a notification that the task started
    vTaskDelay(10);
    if(xTaskGetTickCount() - waketime >= period)
      Serial.println("Overload in task 1");

    vTaskDelayUntil(&waketime, period);

  }

}

void task2(void *pvParameters) {

  (void) pvParameters;
  TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;

  waketime = xTaskGetTickCount();

  while(1) {

    Serial.println('E'); //This happens almost immediately, so we need to add an artificial delay, a  to simulate a task running for a few ms, it only serves as a notification that the task started
    vTaskDelay(10);
    if(xTaskGetTickCount() - waketime >= period) Serial.println("Overload in task 2");
    vTaskDelayUntil(&waketime, period);

  }

}

void task3(void *pvParameters) {

  (void) pvParameters;
  TickType_t waketime, period = 1000 / portTICK_PERIOD_MS;

  waketime = xTaskGetTickCount();

  while(1) {

    Serial.println('S'); //This happens almost immediately, so we need to add an artificial delay, a  to simulate a task running for a few ms, it only serves as a notification that the task started
    vTaskDelay(10);
    if(xTaskGetTickCount() - waketime >= period) Serial.println("Overload in task 3");
    vTaskDelayUntil(&waketime, period);

  }

}
```

I tried increasing the task stack memory in xtaskcreate and the same error occurs, although when I increased it to 1024 nothing shows up in the serial monitor. This same program works flawlessly on arduino uno and raspberry pi pico. I also tried changing the tasks' period and their execution time, which is the delay, and it still doesn't work

title: Why am I receiving this Error: Debug exception reason: Stack canary watchpoint triggered (task1) in ESP32 using a FreeRTOS program?

Answers: 1

body:
> although when I increased it to 1024 nothing shows up in the serial monitor.

Doing nothing to your code except using 4096 for stack size causes it to print things on serial.

```txt
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13864
load:0x40080400,len:3608
entry 0x400805f0
111111
222222M

E
S
S
E
M
S
ME
```

I won't tell you that it's correct, but it seems fairly clear that you haven't given it enough stack to work with.

With my current setup
```c++
Serial.println(configMINIMAL_STACK_SIZE);
```
is printing 828. I don't know how exactly how to interpret that number. But unless I found otherwise, I could default to considering it the requirement to start a task that uses no stack of it own (no local variables, no calling). The memories of the esp32 seem large enough that no matter how you're using them it doesn't make sense to go so minimal for a handful to tasks. I chose 4096 somewhat arbitrarily. I'm not suggesting is a good value.


body:
"Use an Arduino, two potentiometers, and an alarm. Make one of the potentiometers act like a volume control, and make the other potentiometer control the tone that the alarm makes."
I added what I have so far. I'm not sure how to control the volume

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/sqbxe.png

title: Pls help with this prompt. I've been struggling last 2 days with this and its due tomorrow

Answers: 1

body: Use the other potentiometer as a variable resistor. Instead of connecting to pins 1 and 3 (to control tone), Use the 2nd pin of the potentiometer to make a voltage divider. From the 3rd pin go to a + on a buzzer. I don't see the reason to have the circuit connected the way you have. if you want to control the tone with potentiometer, connect it to stable 5v, and connect the second pin with any analog pins that is configured as input. Then, use map function, and map the voltage, accordingly to the tone you'd like to use.