title: Issues getting WPS working on ESP32

text:
# Question
Title: Issues getting WPS working on ESP32
I am trying to implement WPS on ESP32. A WT32-SC01 Plus to be exact. It seems to working so far that I'll get the WPS connection but then it takes around 5 minutes \[!!!\] to get IP address from the router. Also when the WPS connection was successful, after a reboot it do not reconnect but expects a new WPS initialization.

Can you take a look and tell me what am I doing wrong.

Here is my code:

```
#include "WiFi.h"
#include "esp_wps.h"

#define ESP_MANUFACTURER  "ESPRESSIF"
#define ESP_MODEL_NUMBER  "ESP32"
#define ESP_MODEL_NAME    "ESPRESSIF IOT"
#define ESP_DEVICE_NAME   "ESP STATION"

struct WiFiHandler
{
    bool connected = false;
    bool connecting = true;
    bool wpsDone = false;

    WiFiHandler()
    {
        WiFi.mode( WIFI_STA );
        // WiFi.setAutoReconnect( false );
        WiFi.onEvent( [ = ] ( WiFiEvent_t event, arduino_event_info_t info ) -> void
        {
            switch( event ) {
                case ARDUINO_EVENT_WIFI_STA_START:
                    Output::Message( "Station Mode Started" );
                break;
                case ARDUINO_EVENT_WPS_ER_PIN:
                    Output::Message( "PIN: %d", info.wps_er_pin.pin_code );
                break;
                case ARDUINO_EVENT_WIFI_STA_GOT_IP:
                    Output::StartUpMsg( "Connected" );
                    connected = true;
                    connecting = false;
                break;
                case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
                    Output::Message( "Reconnecting" );
                    WiFi.reconnect();
                break;
                case ARDUINO_EVENT_WPS_ER_SUCCESS:
                    Output::StartUpMsg( "WPS Successfull." );
                    WiFi.disconnect();
                    wpsStop();
                    WiFi.begin();
                    wpsDone = true;
                break;
                case ARDUINO_EVENT_WPS_ER_FAILED:
                    Output::StartUpMsg( "WPS Failed!" );
                    connecting = false;
                break;
                case ARDUINO_EVENT_WPS_ER_TIMEOUT:
                    Output::StartUpMsg( "WPS Timedout!" );
                    connecting = false;
                break;
            }
        } );
    }

    bool initialise()
    {
        int cnt = 0;
        TaskHandle_t taskHandle = NULL;
        xTaskCreate( this->blink, "WiFiConnect", 1000, this, 1, &taskHandle );
        Output::StartUpMsg( "Establishing network connection ..." );

        if( String( WiFi.SSID().c_str() ).length() ) {
            WiFi.begin( WiFi.SSID().c_str(), WiFi.psk().c_str() );
            while( ( WiFi.reconnect() != ESP_OK && !this->connected ) && ( ++cnt < 20 ) ) {
                lv_bar_set_value( ui_BootProgress, lv_bar_get_value( ui_BootProgress ) + 1, LV_ANIM_ON );
                delay( 100 );
            }
        }
        if( !this->connected ) {
            WiFi.begin();
            Output::StartUpMsg( "Please initialise WPS connection on the router." );
            cnt = 0;
            if( wpsInit() ) {
                if( esp_wifi_wps_start( 1000 ) != ESP_OK ) {
                    Output::StartUpMsg( "Can't start WPS" );
                }
                while( WiFi.status() != WL_CONNECTED )
                {
                    delay( 1000 );
                    if( WiFi.status() == WL_IDLE_STATUS && wpsDone ) {
                        WiFi.reconnect();
                    }
                    // if( WiFi.status() == WL_CONNECTION_LOST && wpsDone ) {
                    //     WiFi.disconnect();
                    //     WiFi.begin( WiFi.SSID().c_str(), WiFi.psk().c_str() );
                    // }
                    Output::Message( WiFi.SSID().c_str() );
                    Output::Message( WiFi.localIP().toString().c_str() );
                    Output::Message( String( WiFi.status() ).c_str() );
                }
                delay( 2000 );
                this->connected = true;
            }
        }
        if( this->connected ) {
            while ( !WiFi.SSID().length() )
            {
                lv_bar_set_value( ui_BootProgress, lv_bar_get_value( ui_BootProgress ) + 1, LV_ANIM_ON );
                delay( 100 );
            }
            Output::StartUpMsg( "Connected to: " + WiFi.SSID() );
            while ( !String( WiFi.localIP() ).length() || WiFi.localIP().toString() == "0.0.0.0" )
            {
                lv_bar_set_value( ui_BootProgress, lv_bar_get_value( ui_BootProgress ) + 1, LV_ANIM_ON );
                delay( 100 );
            }
            Output::StartUpMsg( "IP: " + String( WiFi.localIP().toString() ) );
            delay( 500 );
            this->connecting = false;
            this->connected = true;
        }
        return this->connected;
    }

    String getIP()
    {
        return String( WiFi.localIP().toString() );
    }

    String getPass()
    {
        return String( WiFi.psk().c_str() );
    }

    String getNetworkName()
    {
        return String( WiFi.SSID() );
    }

    String getMAC()
    {
        return String( WiFi.macAddress() );
    }

    static void blink( void *pvParameter )
    {
        WiFiHandler *l_pThis = ( WiFiHandler * ) pvParameter;
        for( int i = 0; l_pThis->connecting; i++ )  {
            i%2 ? lv_obj_add_flag( ui_WiFiStatus1, LV_OBJ_FLAG_HIDDEN ) : lv_obj_clear_flag( ui_WiFiStatus1, LV_OBJ_FLAG_HIDDEN );
            delay( 250 );
        }
        l_pThis->connected ? lv_obj_clear_flag( ui_WiFiStatus1, LV_OBJ_FLAG_HIDDEN ) : lv_obj_add_flag( ui_WiFiStatus1, LV_OBJ_FLAG_HIDDEN );
        vTaskDelete( NULL );
    }

    static bool wpsInit()
    {
        int cnt = 0;
        esp_wps_config_t config;
        config.wps_type = WPS_TYPE_PBC;
        strcpy( config.factory_info.manufacturer, ESP_MANUFACTURER );
        strcpy( config.factory_info.model_number, ESP_MODEL_NUMBER );
        strcpy( config.factory_info.model_name, ESP_MODEL_NAME );
        strcpy( config.factory_info.device_name, ESP_DEVICE_NAME );
        esp_err_t status = esp_wifi_wps_enable( &config );

        if( status != ESP_OK ) {
            Output::StartUpMsg( "WPS config failed! " + String( esp_err_to_name( status ) ) );
            return false;
        }
        return true;
    }

    static void wpsStop()
    {
        if( esp_wifi_wps_disable() ) {
            Output::StartUpMsg( "WPS Disable Failed" );
        }
    }
};

```

# Answer
Ok people, my router was apparently acting weird. It seems to works fine now!

EDIT: Why the hell someone downvoted my answer? people are weird
> -1 votes

---
Tags: esp32, wifi
---


# Question
Title: How to run avr-gcov on a .ino sketch file
I am new to Arduino and gcov. I have a `.ino` sketch file, `avr-gcov`, and `avr-gcc` from Arduino library in the same directory. Could someone guide me to the steps I should take to run `avr-gcov` on my `.ino` file and get a `.gcov` file?

These are the things I have tried so far. When I run

`./avr-gcov filename.ino`,

it throws the error `filename.gcno: cannot open notes file`. My assumption was that I needed create a `.gcno` file before running gcov. So I tried to create one using the command

`./avr-gcc -c -Wall -pg -fprofile-arcs -ftest-coverage filename.ino`.

But doing so gives a warning: linker input file unused because linking not done and doesn't produce anything.

I tried to create an object code from the sketch file by passing `-o` flag but that throws the error `avr-gcc: fatal error: -fuse-linker-plugin, but liblto_plugin.so not found`.

Any help would be appreciated.

# Answer
> 2 votes
Code coverage by "gcov" has some prerequisites:

1. Instrumented code to count the number the control flow reaches certain points of the program. This is done via the options you tried.
2. Linking with the support library. This is done via the options you tried. The result is a "gcno" file for each translation unit.
3. This support library expects a file system to store the accumulated counter values.
4. Running the application, the support library creates a "gcda" file for each translation unit. This file holds the accumulated counter values.
5. "gcov" expects all these "gcno" and "gcda" files to generate an annotated listing.

Since common Arduinos don't have a file system, the prerequisites cannot be fulfilled. This is the reason why you receive the error messages.

So what can you do now? There are multiple alternatives, but this site is not appropriate to present you ready-made solutions.

1. You can compile the sketch for the PC. For this you need to provide all used Arduino functions, for example as mocks or simulation.
2. You can provide the missing functions on your own, some kind of persistent storage, and finally transfer the data as "gcda" files to your PC. (This sounds complicated and resource expensive, and it is. However, it's doable, I did this years ago with another embedded system and a former version of "gcov".)
3. Refrain from using "gcov" and try other approaches of finding your hot spots. For example, toggle different port pins and/or with different patterns to literally "see" which code is executed. You need a good oscilloscope or logic analyzer for this.

---
Tags: avr-gcc
---


# Question
Title: What is the ideal way to check if time on ESP8266 via NTP is ready?
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);
      }

//..

}

```

# Answer
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 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.
> 3 votes

# Answer
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:

```
// 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;
}

```
> 3 votes

# Answer
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"},

```
> 1 votes

# Answer
**Continuation of timezones:**

```
        {"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

```
> -1 votes

---
Tags: esp8266, time
---


# Question
Title: How can I get a unique ID for all my Arduino boards?
Once you have uploaded a sketch to one of your Arduino boards, it is hard to know exactly what source code led to that sketch.

Indeed, you may change the source code of your sketch on your PC without updating it (in binary format) to your board.

I had the idea of setting up a kind of "*sketch repository*" that would be populated as soon as I upload a sketch to one of my boards. Then I could retrieve, later on, the source code for a sketch running on any of my boards.

For such a repository, I would first need to have an "*index*" that would enable me to know **which board** the sketch source code is linked to.

Typically, such an index should be unique for every single arduino board.

Hence my question: how can I get a unique ID for an Arduino board?

**Edit:**

This is my current list of boards (the miniumum list to be supported by a single unique ID approach):

* UNO R3
* Mega 2560
* Yun
* Arduino Robot (that must be 2 Leonardo equivalent boards)

In the future, I may also build my own boards (Uno equivalent but barebones, without FTDI), hence if an approach also supports these that would be better.

# Answer
There are a number of techniques you could use here to get a unique ID.

1. FTDI chips have a unique serial number programmed onto them. This can only be accessed from the PC side of the connection as far as I am aware.
2. Some of the chips with built in USB (e.g. ATmega8U2/16U2/32U2) have a unique ID in the signature data, normally used for USB. Can easily be accessed from both sides of the connection. This includes the ATmega16U2 that is used as the USB-\>Serial bridge Arduino Uno R3.
3. Some of the chips with built in USB but no unique ID in the signature will still have a unique ID programmed into the USB stack (e.g. LUFA) used for the bootloader or DFU (Device Firmware Upgrade).
4. There are many chips with globally unique serial IDs in them e.g. the Microchip 11AA02E48, all of the Dallas 1-Wire sensors (including the common DS18B20 temperature sensor), and other serial EEPROMS. I've used these in production hardware that must have a unique MAC address.
5. You could modify the standard Optiboot bootloader (or whichever boat loader you use) so that it can hold and respond with a unique ID.

The problem with these is that there is no option except 5 that will work across all boards.

If your solution is going to be a generic one, I would suggest that using a USB ID is not the way forwards. I have ~30 Arduino-based boards, and only 5 of them have built in USB hardware. All the rest of them need an external FTDI cable to be programmed. This means they would all have the same ID.
> 16 votes

# Answer
The chip doesn't have any sort of unique ID as far as I know.... but you could program one into the EEPROM of your boards.

EEPROM documetnation

You would write to a specific address and then future sketches can read the ID and do whatever with it.

---

You may also be able to see a unqiue ID or address on the host side. I don't know enough about USB devices to tell you more, but the chip handling USB communication might have a unique ID you could use. Your Arduino code would not be able to use this, though.

Alternatively, just use a label maker and put a label on each board.
> 13 votes

# Answer
Some boards, when connected to a computer, publish their serial number. My Arduino Uno R3 says

```
[16818.451423] usb 3-2: SerialNumber: 85235353137351E02242

```

Though I'm not sure how unique it is.
> 8 votes

# Answer
To the best of my knowledge the USB chips all come with a unique serial number, at least for the FTDI chips. On Linux you can easily assign unique device names from that, check my website.

Other than that, what you are describing is pretty much a simple form of version control. Make sure your source files have version numbers. To identify your Arduino, you can make it `Serial.Print();` name and version of the code during `setup();`.
> 4 votes

# Answer
I doubt that the USB interface on the Uno gives you a unique serial number. Any number would be part of the code uploaded to the chip which would therefore be the same amongst multiple Unos.

One approach is the DS2401 "Silicon Serial Number" chip which uses the One-wire interface. That would only require one free pin, and some code (the code would be the problem, possibly).

The least intrusive method, and probably the most reliable, would be to simply read back the code and sum-check it. That is exactly what I do with my chip signature detector. However that only detects (as currently written) the bootloader signature. A fairly minor change and it could MD5-sum the entire sketch code.

Example output:

```
Signature detector.
Written by Nick Gammon.
Signature = 1E  95  0F
Fuses
Low = FF High = D6 Ext = FF Lock = CF

Processor = ATmega328P
Flash memory size = 32768
Bootloader in use: Yes
EEPROM preserved through erase: Yes
Watchdog timer always on: No
Bootloader is 512 bytes starting at 7E00

Bootloader:

7E00: 02 01 02 03 0405 06 07 08 09 0A 0B 0C 0D 0E 0F
7E10: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
7E20: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
7E30: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
...
7FB0: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
7FC0: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
7FD0: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
7FE0: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
7FF0: 02 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

MD5 sum of bootloader = 56 72 75 2D 5D B5 0D BA 25 10 DF BE 87 D2 A1 27

```

That MD5 sum (last line) is effectively the signature of that particular bootloader. In fact the most recent version looks them up in a table:

```
MD5 sum of bootloader = FB F4 9B 7B 59 73 7F 65 E8 D0 F8 A5 08 12 E7 9F
Bootloader name: optiboot_atmega328

```

---

So what you could do is, when uploading a sketch, generate a MD5 sum of the hex code. There are fairly simple ways of doing that. Then you could do a "git tag" operation on your source code, and then (using some automated or manual process) remember that a particular MD5 sum of hex code represents the sketch code at a particular moment.

Some sort of database like:

```
Chip: Uno
MD5 sum: D8 8C 70 6D FE 1F DC 38 82 1E CE AE 23 B2 E6 E7
Sketch: My_robot_sketch_42.ino
Git tag: version666

```

Now to locate the source from the board, you establish the MD5 sum of the code (by reading it back from the board) and then look it up in your database.
> 2 votes

# Answer
I connected a one wire temp sensor that each come with an unique I'd. All the sketches read the I'd on boot and wrote the address on every serial connection. I made a shield with all the hardware I needed so if I needed to upgrade from Uno to Mega the device kept its unique I'd.
> 1 votes

# Answer
There is tiny library for reading and writing your custom hardware ID to EEPROM. You can use it to avoid pushing wrong sketch to your Arduino or to identify device for other purposes.

https://github.com/skoumalcz/arduino-id-guard

Disclaimer: I'm author of the library :-)
> 1 votes

# Answer
```
#include <avr/boot.h>
#ifdef __AVR_ATmega2560__  /// check if a MEGA2560 is in use
#define USEMEGA_ID         ///
void setup()
{
#ifdef __AVR_ATmega2560__
  cli();
  int data3, data4;
  data3 = boot_signature_byte_get(0x04) * 256;
  data4 = boot_signature_byte_get(0x01);
  sei();
  MegaID = data3 + data4;
#endif
Serial.begin(115200);
  Serial.print("MegaID             \t: "); Serial.println(MegaID);
}

// This will show you a 3 digit MegaID
// You can now create different setups for different MEGA2560  with the same source code

```
> 0 votes

---
Tags: arduino-uno, arduino-mega, arduino-yun, system-design
---


title: IRRemote send and receive same Arduino

text:
# Question
Title: IRRemote send and receive same Arduino
I am an Arduino (and C/C++) newbie so apologies if I am missing something obvious.

I am using IRremote (github link) as my IR library.

I can get the simple send and receive demos working individually.

However, I cannot get send AND receive working in the same Arduino at the same time.

I do not wish to do something like the "IRrecord" example but what I do want to do is have Arduino send and receive at all times and then trigger alarm/LED once the "beam" is broken.

I am using a TSOP 22 series as my IR receiver. I have tried to use protothreads but no luck. Any tips appreciated.

My current code snippet:

```
#include <IRremote.h>

int RECV_PIN = 11;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("IR Receiver... Started");
}

void loop() {
  //single threaded nature seems to break below

  // i want to start receiver here
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
  }
  //delay(5000);

  //trying to send here
  for (int i = 0; i < 3; i++) {
    irsend.sendSony(0xa90, 12);
    Serial.println("Sent Sony......");
    delay(40);
  }
  //delay(5000); //5 second delay between each signal burst
}

```

# Answer
> 5 votes
I managed to do this using solution from Ken Sheriff's Blog. Ken provides a simple example and documents it perfectly. Due to the nature of my IR Receiver (rejecting continuous beam) I used the sample code provided by Stephane Deniaud in the comments section. Thanks to both...

```
#include <IRremote.h>

#define PIN_DETECT 2
IRsend irsend;

void setup()
{
    pinMode(PIN_DETECT, INPUT);

    Serial.begin(115200);
    Serial.println("READY");

    attachInterrupt(digitalPinToInterrupt(PIN_DETECT), checkIRBeamBreak, RISING);

    // Note : the IR emitter is on PIN #3
    irsend.enableIROut(38);
    IREmitterOn();
}

// Use this function instead of delay() as delay() does not work in interrupt callbacks
void pause(int ms) {
    // We need a loop as the largest value for delayMicroseconds that will produce an accurate delay is 16383
    for (int i = 0; i < ms; i++) {
        delayMicroseconds(1000);
    }
}

void IREmitterOff() {
    irsend.space(0);
    pause(60); // 60 ms is OK for my TSOP but should be tuned
}

void IREmitterOn() {
    irsend.mark(0);
    pause(10);
}

void switchOffOnIREmitter() {
    IREmitterOff();
    IREmitterOn();
}

void checkIRBeamBreak() {
    int val = digitalRead(PIN_DETECT);
    // LOW : no beam break
    // HIGH : beam break
    if (val == LOW)
        return;

    detachInterrupt(digitalPinToInterrupt(PIN_DETECT));
    switchOffOnIREmitter();
    if (digitalRead(PIN_DETECT) == HIGH) {
        Serial.println("IR BEAM BREAK !!!!");
    }
    attachInterrupt(digitalPinToInterrupt(PIN_DETECT), checkIRBeamBreak, RISING);
}

void loop() {

}

```

# Answer
> 2 votes
based on the concept of user1843591 answer, i researched some more and found the example of Nick Gammon in the arduino forum.

after some tweaks i came up with the following: (based on both) it uses Timer1 to generate a 38kHz signal and Timer2 to generate a 760Hz cycle that switches the 38kHz signal on and off. this way the recommend pulse-cycles and gap times for the Receiver (for me TSOP4438) is preserve. it also implements *global flags* to decouple the ISRs & mainloop.

(both files should be in a folder `IR_TSOP4438_light_barrier`)

`IR_TSOP4438_light_barrier.ino`

```
// simple light barrier test

extern volatile bool light_barrier_broken;

void setup(){
    Serial.begin(115200);
    Serial.println("IR_TSOP4438_light_barrier");
    Serial.println("setup...");
    setupIRLightBarrier();
    Serial.println("running.");
}

void loop() {
  if(light_barrier_broken) {
    Serial.println("light barrier 1 break detected");
    delay(20);
    digitalWrite (LED_BUILTIN, LOW);
    light_barrier_broken = false;
  }
}

```

`ir_light_barrier.ino`

```
// based on
// Example of modulating a 38 KHz carrier frequency at 500 Hz with a variable duty cycle
// Author: Nick Gammon
// Date: 24 September 2012
// https://forum.arduino.cc/t/how-to-create-a-38-khz-pulse-with-arduino-using-timer-or-pwm/100217/44

// tweaked for TSOP4438
// https://www.vishay.com/docs/82459/tsop48.pdf
// find max burst length and min gap times:
//
// Minimum burst length 10 cycles/burst
// After each burst of length 10 to 40 cycles
//  a minimum gap time is required of ≥ 10 cycles
// Maximum number of continuous short bursts/second: 1500
//
// translates to:
// 38kHz = 26,3 us / Pulse → *10= 263us
// max burst length: <= 1052us  (26,3*40)
// min gap   length: >=  263us  (26,3*10)
// total cycle time of (1052+263=) 1315us
// that violates the max bursts/second (666us/burst)
//
// on option is to optimize for the most bursts/second:
// so we use the min gap time as given and use the rest of the available time.
// 666us - 263us = 403 us burst length
// hopefully this way the AGC does not filter our stream...
// we now have to fit this to the best available prescaler / counter values:
// 672us fits good (this way we have less than the 1500 burst)
// this translates to 42 counts a' (0,0625us*256=) 16us
// so we use a gap length of 16us*17 = 272us
// this gives us a burst length of 16us*(42-17)= 400us
//
// second option is to optimize for the longest burst length and have less bursts/second.
// here we will use a in-between leaning towards longer bursts:
// 0,0625us*256=16us
// 16us*50counts =  800us = 0,80ms = 1250,00Hz = 1250bursts/s
// 16us*80counts = 1280us = 1,28ms =  781,25Hz = 781,25bursts/s
// gap   length: 16us*17      =  272us
// burst length: 16us*(80-17) = 1008us

// http://www.gammon.com.au/forum/?id=11504
// Timer 1
//   OC1A: D9
//   OC1B: D10
const byte LED = 9;

// Timer 2 (8bit)
//   OC2A: D11
//   OC2B: D3

// https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
const byte light_barrier_PIN = 2;
// const byte light_barrier_PIN = 3;

// global flags to be handled in the main loop...
volatile bool light_barrier_broken = false;

// Clock frequency divided by 38 kHz frequency desired
const long timer1_OCR1A_Setting = F_CPU / 38000L;
// (16000000 / 38000) = 421,05
// this only works on Timer 1 - as it is a 16bit timer.

// // ------------------------------------------
// // this is about the slowest possible setting.
// // timer2 target counts:
// // CPU          16MHz (0,0625us)
// // target       63Hz (16000us = 16ms)
// // prescaler    1024
// const long timer2_top = F_CPU / 63L / 1024;
// // (16000000 / 63 / 1024) = 250

// // ------------------------------------------
// // optimized for ~1500 bursts /second
// // target counts:
// // CPU          16MHz (0,0625us)
// // prescaler    256
// // target       1,488kHz (672us = 0,672ms)
// const long timer2_top = (F_CPU / 256L) / 1488L;
// // (16000000 / 256) / 1488 = 42
// // calculate on / off ratio (toggle point)
// const long timer2_compare = timer2_top * 400L / 672L;
// // 42 * 400 / 672   = 42 - 17   = 25

// ------------------------------------------
// in-between -  leaning for longer bursts
// target counts:
// CPU          16MHz (0,0625us)
// prescaler    256
// target       781kHz (1280us = 1,28ms)
const long timer2_top = (F_CPU / 256L) / 781L;
// (16000000 / 256) / 781 = 80
// calculate on / off ratio (toggle point)
const long timer2_compare = timer2_top * 1008L / 1280L;
// 80 * 1008 / 1280   =  80 - 17  =  63

volatile bool sender_active = false;

void light_barrier_ISR() {
    if (
        sender_active
        && digitalRead(light_barrier_PIN) == HIGH
    ) {
        digitalWrite (LED_BUILTIN, HIGH);
        light_barrier_broken = true;
        // if() {
        // }
    } else {
        digitalWrite (LED_BUILTIN, LOW);
    }
}

ISR (TIMER2_COMPA_vect) {
    // used to combine the two timers...

    // toggle D13
    // PINB = bit (5);
    // digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)) ;

    if (sender_active == false) {
        // enable timer1 output
        TCCR1A |= bit(COM1A0) ;  // Toggle OC1A on Compare Match
        // digitalWrite (LED_BUILTIN, HIGH);
        delayMicroseconds(100);
        sender_active = true;
    } else {
        sender_active = false;
        delayMicroseconds(100);
        // disable IR-Receiver Input check
        //detachInterrupt(digitalPinToInterrupt(light_barrier_PIN));
        // disable timer1 output
        TCCR1A &= ~bit(COM1A0) ;  // DO NOT Toggle OC1A on Compare Match
        digitalWrite (LED, LOW);  // ensure off
        // digitalWrite (LED_BUILTIN, LOW);
    }
}

void setupIRLightBarrier() {
    pinMode(LED, OUTPUT);
    digitalWrite(LED, LOW);
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);

    // set up Timer 1 - gives us 38.095 KHz
    TCCR1A = bit (COM1A0); // toggle OC1A on compare
    TCCR1B = _BV(WGM12) | _BV (CS10);   // CTC to OCR1A, No prescaler
    OCR1A =  (16000000L / 38000L / 2) - 1;  // zero relative

    // setup Timer 2
    TCCR2A = 0;
    TCCR2B = 0;
    // toggle OC2A on compare
    // TCCR2A |= bit(COM2A0);
    // fast pwm to OCR2A
    TCCR2A |= bit(WGM21) | bit(WGM20);
    TCCR2B |= bit(WGM22);
    // prescaler 1024
    // TCCR2B |= bit(CS22) | bit(CS21) | bit(CS20);
    // prescaler 265
    TCCR2B |= bit(CS22) | bit(CS21);
    // top
    OCR2A = timer2_top - 1;  // zero relative
    // switch point
    OCR2B = timer2_compare - 1;  // zero relative
    // enable interrupts
    TIMSK2 = bit(OCIE2A);
    // TIMSK2 = bit(OCIE2B) | bit(OCIE2A);

    // enable IR-Receiver Input check
    attachInterrupt(
        digitalPinToInterrupt(light_barrier_PIN),
        light_barrier_ISR,
        CHANGE
    );
}

```

# Answer
> 1 votes
I **THINK** the problem is that the Arduino takes some time (very minimal) to send the signal, but when it comes to receive it, the signal has already dissipated though your room.

---

> send and receive at all times and then trigger alarm/LED once the "beam" is broken.

Use a laser, it's cheaper, more acurate, and more "James Bond'ish'" :)

---
Tags: arduino-uno, programming, c++
---


# Question
Title: How to scroll text on an OLED display using only the SSD1306Wire library?
I'm a 13 years old boy and I am doing a project with esp01 and an OLED screen to display project ideas on the OLED with the ChatGPT API. The answer is displayed on the OLED but I would like it to scroll from bottom to top and so on to the next query so I can see the whole answer.I noted that the only library that worked for me for the esp01 was the SSD1306Wire library .My code is :

```
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <Wire.h>
#include <SSD1306Wire.h>
#include <ArduinoJson.h>

const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";

const char* apiEndpoint = "https://api.openai.com/v1/engines/text-davinci-002/completions";
const char* apiToken = "OPENAI_TOKEN";

SSD1306Wire  display(0x3c, 2, 0);
void setup() {
 Serial.begin(115200);

 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
   delay(1000);
   Serial.println("Connecting to WiFi...");
 }

 Serial.println("Connected to WiFi");

 display.init();
 display.flipScreenVertically();
 display.setFont(ArialMT_Plain_10);
}

void loop() {
 WiFiClientSecure client;
 client.setInsecure();
 HTTPClient http;
 http.begin(client, apiEndpoint);
 http.addHeader("Content-Type", "application/json");
 http.addHeader("Authorization", "Bearer " + String(apiToken));
 String payload = "{\"prompt\": \"TEXT_TO_QUERY\",\"temperature\":0.8,\"max_tokens\":40}";
 int httpResponseCode = http.POST(payload);
 String response = "";

 if (httpResponseCode == 200) {
   response = http.getString();
   int startIndex = response.indexOf("text\":") + 7;
   int endIndex = response.indexOf("\",\"index\"");
   response = response.substring(startIndex, endIndex);
   response.replace("\\n", "\n");
   Serial.println(response);
 } else {
   Serial.print("Error: ");
   Serial.println(httpResponseCode);
 }

 http.end();

 display.clear();
 display.drawStringMaxWidth(0, 0, 128, response);
 display.display();

 delay(18000000);
}

```

Could anyone help me?

# Answer

> 0 votes

---
Tags: esp8266, display, oled
---


# Question
Title: ESP32 - BLE does not connect/restart after light sleep
noob in arduino here.

I'm trying to connect via BLE after the ESP32 wakeups from light sleep. I have tried many different things, but none of them work. Everything works fine before the device sleeps the first time. Could you guys please give some ideas of what is wrong? the official docs are terrible.

```

    btStop();
    delay(1000);
    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
    Serial.println("Going to light sleep now");
    esp_light_sleep_start();
    btStart();

```

# Answer
I finally found the answer, you just need to advertise again the service after it sleeps. First you need to define this:

```
#if CONFIG_PM_ENABLE
// Configure dynamic frequency scaling:
// maximum and minimum frequencies are set in sdkconfig,
// automatic light sleep is enabled if tickless idle support is enabled.
// esp_pm_config_esp32c3_t pm_config = { // old version
esp_pm_config_t pm_config = {
        .max_freq_mhz = 160, //  e.g. 80, 160,
        .min_freq_mhz = 80, // 40
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
        .light_sleep_enable = true
#endif
    };
ESP_ERROR_CHECK( esp_pm_configure(&pm_config) );
#endif // CONFIG_PM_ENABLE

```

Then in your loop you could do something like:

```
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Going to light sleep now");
esp_light_sleep_start();
Serial.println("depois do sleep start");
BLEDevice::startAdvertising();

```
> 0 votes

---
Tags: esp32, ble
---


title: Reading/writing Ntag215 with RC522

text:
# Question
Title: Reading/writing Ntag215 with RC522
I ordered Ntag215 from Aliexpress. The tags are identified just fine, yet I have issues writing/reading to them because of failed authentication. I am using Arduino Uno + RFID-RC522 module. This is my code below:

```
#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 9  //
#define SS_PIN 10  //

MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance

void setup() {
  Serial.begin(9600);  // Initialize serial communications with the PC
  while (!Serial)
    ;                  // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  SPI.begin();         // Init SPI bus
  mfrc522.PCD_Init();  // Init MFRC522
  Serial.println(F("Scan PICC to see UID, type, and data blocks..."));
}

void loop() {
  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }
  Serial.print(F("Card UID:"));
  dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  Serial.println();
  Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));

  MFRC522::MIFARE_Key key = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  MFRC522::StatusCode status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid));
  Serial.println(mfrc522.GetStatusCodeName(status));
}

void dump_byte_array(byte *buffer, byte bufferSize) {
    for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
    }
}

```

And this is the output I get.

```
01:27:26.704 -> Scan PICC to see UID, type, and data blocks...
01:27:30.357 -> Card UID: 04 CB 4A 57 19 61 80
01:27:30.390 -> PICC type: MIFARE Ultralight or Ultralight C
01:27:30.422 -> Timeout in communication.

```

Always get Timeout in communication. With Mifare 1KB tags this is not an issue. Any idea?

# Answer
> 1 votes
Ok after more trial and error and research I have made it possible to Write and Read to Ntag215. Here are code snippets for writing and reading. It was not required to Authenticate to write the data the tag.

Writing: It is actually quite simple. The main rule is that the writing can start from the page 4. And the bufferSize has to be 4. Here is example just writing "A" character to the tag.

```
    char charToProgram = "A";
    byte data = charToProgram;       // Data to write (ASCII character "A")
    byte blockAddr = 4;  // Block address to write to

    // Write the data to the tag
    MFRC522::StatusCode status = reader.MIFARE_Ultralight_Write(4, &data, 4);

    if (status == MFRC522::StatusCode::STATUS_OK) {
      Serial.println("SUCCESS! Wrote to card!");
      reader.PICC_HaltA();
    }

```

Reading:

```
    int blockAddr = 4;  // Block address to read from
    byte data[18];
    byte size = 18;
    // Write the data to the tag
    MFRC522::StatusCode status = reader.MIFARE_Read(blockAddr, data, &size);

    if (status == MFRC522::StatusCode::STATUS_OK) {
      Serial.print("Read character: ");
      Serial.println((char) data[0]);
      reader.PICC_HaltA();
    }

```

---
Tags: arduino-uno, rfid
---


# Question
Title: Potential difference across the same wire
This issue may be weird, and I'm not sure if this is because of my wiring, but it would seem that **I do not have the same voltage** (or approximately the same voltage) between the **VCC(3.3V)** and the **VCC power rail** of my breadboard.

When measuring the voltage, there is **~0.300 mV** difference. And indeed measuring VCC and GND gives me **2.9 V**, instead of **3.3 V**

* I measured the flat jumper, it **doesn't have any resistance** (~~0)
* The ESP is consuming **below 100mA**, so no voltage drop

Could anyone explain me that ? See attached pictures

# Answer
The only reasonable explanation is that the path between the 3.3V pin and the wire you are measuring does indeed have non-zero resistance. The wires look dirty to me from the photo, plus there would be internal resistance in the breadboard connectors.

You are measuring from the 3.3V pin and not the other end of the wire. I suggest using a different wire, or cleaning that one with sandpaper or by filing it down until you see shiny copper. Also try a different pin on the breadboard.

This is really a hardware or measurement issue. There is no way that a wire with zero resistance from one end to the other is going to have a 0.242V drop across it.
> 0 votes

---
Tags: esp32, voltage
---


# Question
Title: esp based smart light system over alexa malfunctioning
i made a home automation system using esp 32 and 8 channel relay but within 2 or 3 months my relay automatically turns off after sending the signal to it through esp32 but if i connect directly without esp32 it functions absolutely fine. that means that my relay if fine but what must be the possible reason for this malfunctioning. this is my code

```
#include <ESP8266WiFi.h>
#include <Espalexa.h>
Espalexa espalexa;

// define the GPIO connected with Relays and switches
#define RelayPin1 5  //D23
#define RelayPin2 4  //D22
#define RelayPin3 0  //D21
#define RelayPin4 2  //D19
#define RelayPin5 14  //D18
#define RelayPin6 12  //D5
#define RelayPin7 13  //D25
#define RelayPin8 15  //D26

#define SwitchPin1 3  //D13
#define SwitchPin2 1  //D12
#define SwitchPin3 10  //D14
#define SwitchPin4 9  //D27
#define SwitchPin5 8  //D33
#define SwitchPin6 11  //D32
#define SwitchPin7 7  //D15
#define SwitchPin8 6   //D4

bool oldStateSwitch_1;
bool oldStateSwitch_2;
bool oldStateSwitch_3;
bool oldStateSwitch_4;
bool oldStateSwitch_5;
bool oldStateSwitch_6;
bool oldStateSwitch_7;
bool oldStateSwitch_8;

#define wifiLed    16   //D2

// WiFi Credentials
const char* ssid = "akkikisu";
const char* password = "anirudh@123";

// device names
String Device_1_Name = "a1";
String Device_2_Name = "a2";
String Device_3_Name = "a3";
String Device_4_Name = "a4";
String Device_5_Name = "a5";
String Device_6_Name = "a6";
String Device_7_Name = "a7";
String Device_8_Name = "a8";

// prototypes
boolean connectWifi();

//callback functions
void firstLightChanged(uint8_t brightness);
void secondLightChanged(uint8_t brightness);
void thirdLightChanged(uint8_t brightness);
void fourthLightChanged(uint8_t brightness);
void fifthLightChanged(uint8_t brightness);
void sixthLightChanged(uint8_t brightness);
void senventhLightChanged(uint8_t brightness);
void eighthLightChanged(uint8_t brightness);

boolean wifiConnected = false;

//our callback functions
void firstLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin1, LOW);
      Serial.println("Device1 ON");
    }
  else
  {
    digitalWrite(RelayPin1, HIGH);
    Serial.println("Device1 OFF");
  }
}

void secondLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin2, LOW);
      Serial.println("Device2 ON");
    }
  else
  {
    digitalWrite(RelayPin2, HIGH);
    Serial.println("Device2 OFF");
  }
}

void thirdLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin3, LOW);
      Serial.println("Device3 ON");
    }
  else
  {
    digitalWrite(RelayPin3, HIGH);
    Serial.println("Device3 OFF");
  }
}

void fourthLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin4, LOW);
      Serial.println("Device4 ON");
    }
  else
  {
    digitalWrite(RelayPin4, HIGH);
    Serial.println("Device4 OFF");
  }
}

void fifthLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin5, LOW);
      Serial.println("Device5 ON");
    }
  else
  {
    digitalWrite(RelayPin5, HIGH);
    Serial.println("Device1 OFF");
  }
}

void sixthLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin6, LOW);
      Serial.println("Device6 ON");
    }
  else
  {
    digitalWrite(RelayPin6, HIGH);
    Serial.println("Device6 OFF");
  }
}

void seventhLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin7, LOW);
      Serial.println("Device7 ON");
    }
  else
  {
    digitalWrite(RelayPin7, HIGH);
    Serial.println("Device7 OFF");
  }
}

void eighthLightChanged(uint8_t brightness)
{
  //Control the device
  if (brightness == 255)
    {
      digitalWrite(RelayPin8, LOW);
      Serial.println("Device8 ON");
    }
  else
  {
    digitalWrite(RelayPin8, HIGH);
    Serial.println("Device8 OFF");
  }
}

// connect to wifi – returns true if successful or false if not
boolean connectWifi()
{
  boolean state = true;
  int i = 0;

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 20) {
      state = false; break;
    }
    i++;
  }
  Serial.println("");
  if (state) {
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
  else {
    Serial.println("Connection failed.");
  }
  return state;
}

void addDevices(){
  // Define your devices here.
  espalexa.addDevice(Device_1_Name, firstLightChanged); //simplest definition, default state off
  espalexa.addDevice(Device_2_Name, secondLightChanged);
  espalexa.addDevice(Device_3_Name, thirdLightChanged);
  espalexa.addDevice(Device_4_Name, fourthLightChanged);
  espalexa.addDevice(Device_5_Name, fifthLightChanged);
  espalexa.addDevice(Device_6_Name, sixthLightChanged);
  espalexa.addDevice(Device_7_Name, seventhLightChanged);
  espalexa.addDevice(Device_8_Name, eighthLightChanged);

  espalexa.begin();
}

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

  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);
  pinMode(RelayPin3, OUTPUT);
  pinMode(RelayPin4, OUTPUT);
  pinMode(RelayPin5, OUTPUT);
  pinMode(RelayPin6, OUTPUT);
  pinMode(RelayPin7, OUTPUT);
  pinMode(RelayPin8, OUTPUT);

  pinMode(wifiLed, OUTPUT);

  pinMode(SwitchPin1, INPUT_PULLUP);
  pinMode(SwitchPin2, INPUT_PULLUP);
  pinMode(SwitchPin3, INPUT_PULLUP);
  pinMode(SwitchPin4, INPUT_PULLUP);
  pinMode(SwitchPin5, INPUT_PULLUP);
  pinMode(SwitchPin6, INPUT_PULLUP);
  pinMode(SwitchPin7, INPUT_PULLUP);
  pinMode(SwitchPin8, INPUT_PULLUP);

  //During Starting all Relays should TURN OFF
  digitalWrite(RelayPin1, HIGH);
  digitalWrite(RelayPin2, HIGH);
  digitalWrite(RelayPin3, HIGH);
  digitalWrite(RelayPin4, HIGH);
  digitalWrite(RelayPin5, HIGH);
  digitalWrite(RelayPin6, HIGH);
  digitalWrite(RelayPin7, HIGH);
  digitalWrite(RelayPin8, HIGH);

  oldStateSwitch_1 = ! digitalRead( SwitchPin1 ) ;  // note inverted
  oldStateSwitch_2 = ! digitalRead( SwitchPin2 ) ;  // note inverted
  oldStateSwitch_3 = ! digitalRead( SwitchPin3 ) ;  // note inverted
  oldStateSwitch_4 = ! digitalRead( SwitchPin4 ) ;  // note inverted
  oldStateSwitch_5 = ! digitalRead( SwitchPin5 ) ;  // note inverted
  oldStateSwitch_6 = ! digitalRead( SwitchPin6 ) ;  // note inverted
  oldStateSwitch_7 = ! digitalRead( SwitchPin7 ) ;  // note inverted
  oldStateSwitch_8 = ! digitalRead( SwitchPin8 ) ;  // note inverted

    // repeat for seitched 2 to 8

  // Initialise wifi connection
  wifiConnected = connectWifi();

  if (wifiConnected)
  {
    addDevices();
  }
  else
  {
    Serial.println("Cannot connect to WiFi. So in Manual Mode");
    delay(1000);
  }
}

void loop()
{
   if (WiFi.status() != WL_CONNECTED)
  {
    //Serial.print("WiFi Not Connected ");
    digitalWrite(wifiLed, LOW); //Turn off WiFi LED
  }
  else
  {
    //Serial.print("WiFi Connected  ");
    digitalWrite(wifiLed, HIGH);
    //Manual Switch Control
    //WiFi Control
    if (wifiConnected){
      espalexa.loop();
      delay(1);
    }
    else {
      wifiConnected = connectWifi(); // Initialise wifi connection
      if(wifiConnected){
      addDevices();
      }
    }
  }

//main code

static uint32_t lastSwitchTest = 0 ;  // static initialised once only

      if ( millis() - lastSwitchTest > 250 ) {  // every 250ms
      lastSwitchTest = millis() ;

      // switch 1

      bool stateSwitch_1 = digitalRead( SwitchPin1 ) ;
      if (  oldStateSwitch_1 != stateSwitch_1 ) {
         oldStateSwitch_1 = stateSwitch_1 ;
         Serial.println("Switch 1 changed");
         EspalexaDevice* d1 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_1 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d1->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin1, HIGH);
         }
         else { // switch on
            Serial.println("Switch 1 on");
            d1->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin1, LOW);
         }
      }

      // switch 2

      bool stateSwitch_2 = digitalRead( SwitchPin2 ) ;
      if ( oldStateSwitch_2 != stateSwitch_2 ) {
         oldStateSwitch_2 = stateSwitch_2 ;
         Serial.println("Switch 2 changed");
         EspalexaDevice* d2 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_2 == HIGH )  {  // HIGH = off
            Serial.println("Switch 2 off");
            d2->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin2, HIGH);
         }
         else { // switch on
            Serial.println("Switch 2 on");
            d2->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin2, LOW);
         }
      }

      // switch 3

      bool stateSwitch_3 = digitalRead( SwitchPin3 ) ;
      if ( oldStateSwitch_3 != stateSwitch_3 ) {
         oldStateSwitch_3 = stateSwitch_3 ;
         Serial.println("Switch 3 changed");
         EspalexaDevice* d3 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_3 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d3->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin3, HIGH);
         }
         else { // switch on
            Serial.println("Switch 3 on");
            d3->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin3, LOW);
         }
      }
      // switch 4

      bool stateSwitch_4 = digitalRead( SwitchPin4 ) ;
      if ( oldStateSwitch_4 != stateSwitch_4 ) {
         oldStateSwitch_4 = stateSwitch_4 ;
         Serial.println("Switch 4 changed");
         EspalexaDevice* d4 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_4 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d4->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin4, HIGH);
         }
         else { // switch on
            Serial.println("Switch 4 on");
            d4->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin4, LOW);
         }
      }
      // switch 5

      bool stateSwitch_5 = digitalRead( SwitchPin5 ) ;
      if ( oldStateSwitch_5 != stateSwitch_5 ) {
         oldStateSwitch_5 = stateSwitch_5 ;
         Serial.println("Switch 5 changed");
         EspalexaDevice* d5 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_5 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d5->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin5, HIGH);
         }
         else { // switch on
            Serial.println("Switch 5 on");
            d5->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin5, LOW);
         }
      }
      // switch 6

      bool stateSwitch_6 = digitalRead( SwitchPin6 ) ;
      if ( oldStateSwitch_6 != stateSwitch_6 ) {
         oldStateSwitch_6 = stateSwitch_6 ;
         Serial.println("Switch 6 changed");
         EspalexaDevice* d6 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_6 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d6->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin6, HIGH);
         }
         else { // switch on
            Serial.println("Switch 6 on");
            d6->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin6, LOW);
         }
      }
      // switch 7

      bool stateSwitch_7 = digitalRead( SwitchPin7 ) ;
      if ( oldStateSwitch_7 != stateSwitch_7 ) {
         oldStateSwitch_7 = stateSwitch_7 ;
         Serial.println("Switch 7 changed");
         EspalexaDevice* d7 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_7 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d7->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin7, HIGH);
         }
         else { // switch on
            Serial.println("Switch 7 on");
            d7->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin7, LOW);
         }
      }
      // switch 8

      bool stateSwitch_8 = digitalRead( SwitchPin8 ) ;
      if ( oldStateSwitch_8 != stateSwitch_8 ) {
         oldStateSwitch_8 = stateSwitch_8 ;
         Serial.println("Switch 8 changed");
         EspalexaDevice* d8 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_8 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d8->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin8, HIGH);
         }
         else { // switch on
            Serial.println("Switch 8 on");
            d8->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin8, LOW);
         }
      }

      // switch 2 to 8
      // just copy/paste/adjust using switch 1 as a template

    } // if ( millis
} // loop()

```

# Answer
You are using the following project as a code base: https://iotcircuithub.com/esp32-alexa-home-automation-system/

You appear to have confirmed that the same problem symptoms appear when the ESP32 is reset, that is that some lights are in the wrong state at system start. A reset can be caused by such things as a system reset following a power outage, a crash or simply pressing the reset button on the device.

You are using a button handling library AceButton.h in combination with latched switches. The problem here is that the button handling library is intended for momentory push-to-make buttons and assumes that the switch is in the "un-pushed" state at system start. This may not reflect the position of the latched switches where some could be in the on position and others in the off position. This could result in missed events on system start.

Anyway, you do not need a button library. Especially for toggle type switches, like you are using, where it is necessary only to read the switch say every 250ms and test if the state has been changed since the last reading. No other debouncing is required.

In setup() you'd read each switch and store the inverse of its current state in a variable, say oldStateSwitch\_1. It is necessary to store the inverse of the state to trigger a first time switch state change action in the loop().

Something like . . .

```
void setup() {
    . . .

    oldStateSwitch_1 = ! digitalRead( switchPin1 ) ;  // note inverted
    // repeat for seitched 2 to 8
    . . .

}

```

In the loop(), you'd do something like . . .

```
void loop() {

. . .
. . .

    static uint32_t lastSwitchTest = 0 ;  // static initialised once only

    if ( millis() - lastSwitchTest > 250 ) {  // every 250ms
      lastSwitchTest = millis() ;

      // switch 1

      bool stateSwitch_1 = digitalRead( switchPin1 ) ;
      if ( oldStateSwitch_1 != stateSwitch_1 ) {
         oldStateSwitch_1 = stateSwitch_1 ;
         Serial.println("Switch 1 changed");
         EspalexaDevice* d1 = espalexa.getDevice(0); //this will get "first device", the index is zero-based
         if ( stateSwitch_1 == HIGH )  {  // HIGH = off
            Serial.println("Switch 1 off");
            d1->setPercent(0); //set value "brightness" in percent
            digitalWrite(RelayPin1, HIGH);
         }
         else { // switch on
            Serial.println("Switch 1 on");
            d1->setPercent(100); //set value "brightness" in percent
            digitalWrite(RelayPin1, LOW);
         }
      }

      // switch 2 to 8
      // just copy/paste/adjust using switch 1 as a template

    } // if ( millis
} // loop()

```

All AceButton code should be deleted.
> 1 votes

---
Tags: esp32, relay, home-automation
---


# Question
Title: Nano 33 BLE Sense powered with Vin and USB at the same time
I have a project where I would like to power an Arduino Nano 33 BLE Sense with USB and Vin at the same time.

The idea is to charge an external LiPo 3.7V through a charger module that would take the load from the 3.3V pin (that would be powered through USB) and at the same time keep powering the Arduino through Vin because I want to avoid a power interruption when I unplugged the USB cable that would interrupt the writing operation (on a text file on an SD card).

So the goal is to prevent data corruption on a writing operation on a text file. I know text files are supposed to be less corruptible (compared to a database) but I want to be sure the operation would be uninterrupted.

I've seen this post: What happens if I power the Arduino with both the USB and external power voltage simultaneously? But it's related to the Arduino UNO R3.

It basically says: When Vin \>6.6V the opamp turns the mosfet off.

> > > so the USB disconnects.

When Vin \<6.6V the opamp turns the mosfet on.

> > > so the USB stays connected.

On Arduino's website: https://store-usa.arduino.cc/products/arduino-nano-33-ble-sense it says:

---

Vin: This pin can be used to power the board with a DC voltage source. If the power is fed through this pin, the USB power source is disconnected.

---

It does not mention from what voltage it would disconnect the USB power.

I did not find the same schematic for the Arduino Nano 33 BLE Sense. Just this:https://docs.arduino.cc/hardware/nano-33-ble-sense

> > > Interactive Viewer Interact with the schematics, the PCB and a 3D model of the product.

and this: https://docs.arduino.cc/static/353d3c445c28b1da1fe1f9d6eafa948d/ABX00031-schematics.pdf

I'm not very familiar with reading schematics but I could not find similar information about vin and USBVCC.

That'd be great if somebody had some insight on that.

I would welcome any suggestion.

Cheers!

---

If I connect a battery charger/controller on VIN, my battery would be protected.

And I could connect a booster 5V and add a shottky diode so its connection to VIN would be closed if booster+ \< VIN

Like this ?

# Answer
In this power block you can see there is only one Schottky diode with the voltage drop under 0.5V@2A. That means D2 is closed around the condition: VUSB \< VIN.

On the other side if you add 3.6-4.2V battery on VIN there will be current flowing from VUSB to battery.

Basically you need another shottky diode Bat+ -\> \[A|K\] -\> VIN so when there is bigger voltage on the VIN it'll "shut off" the battery (otherwise it'll be charged by almost 5V)

Depending on the application and sensors you are planning to use, you might want to consider for example Seeed Studio XIAO nRF52840 Sense that has battery charging circuit and pads for the battery on the bottom (although it's not the "bread board" pins)
> 1 votes

---
Tags: usb, arduino-nano-ble
---


# Question
Title: Arduino nano + 4x 7 segment display + 74HC595 - Only dot points are turn on
I am trying to run a thermometer with thermocouple sensor on Arduino Nano.

I have bought 4x 7 segment display and 74HC595 chip. Everything is connected like in the attached diagram below (without DS18B20) , but when I uploaded sketch to Nano - only dots are turn on .

Below You Can find my code

```
#include <OneWire.h>

const int latchPin = 8; // Pin connected to ST_CP of 74HC595
const int clockPin = 9; // Pin connected to SH_CP of 74HC595
const int dataPin = 10; // Pin connected to DS of 74HC595
const int digitPins[4] = {
    3, 4, 5, 6}; // pins to control the 4 common anode pins of display
// seven segment digit bits + blank + minus
const byte digit[12] = {
    B00111111, // 0
    B00000110, // 1
    B01011011, // 2
    B01001111, // 3
    B01100110, // 4
    B01101101, // 5
    B01111101, // 6
    B00000111, // 7
    B01111111, // 8
    B01101111, // 9
    B00000000, // Blank
    B01000000  //-
};

int digitBuffer[4] = {1};
int digitScan = 0;
int soft_scaler = 0;
float tempC, tempF;
int tmp;
boolean sign = false;

void setup()
{
    TCCR2A = 0;
    TCCR2B = (1 << CS21);
    TIMSK2 = (1 << TOIE2);
    TCNT2 = 0;

    for (int i = 0; i < 4; i++)
        pinMode(digitPins[i], OUTPUT);

    pinMode(latchPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
    pinMode(dataPin, OUTPUT);
}

ISR(TIMER2_OVF_vect)
{
    soft_scaler++;
    if (soft_scaler == 15)
    {
        refreshDisplay();
        soft_scaler = 0;
    }
};

void refreshDisplay()
{
    for (byte k = 0; k < 4; k++)
        digitalWrite(digitPins[k], LOW);

    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
    digitalWrite(latchPin, HIGH);
    delayMicroseconds(50);
    digitalWrite(digitPins[digitScan], HIGH);
    digitalWrite(latchPin, LOW);

    if (digitScan == 1)
    {
        shiftOut(dataPin, clockPin, MSBFIRST,
                 ~(digit[digitBuffer[digitScan]] | B10000000));
    }
    else
    {
        shiftOut(dataPin, clockPin, MSBFIRST, ~digit[digitBuffer[digitScan]]);
    }

    digitalWrite(latchPin, HIGH);
    digitScan++;
    if (digitScan > 3)
        digitScan = 0;
}

void loop()
{

    tempC = 90.8;
    tmp = int(tempC * 10);
    if (tempC < 0)
    {
        sign = true;
        tmp = abs(tmp);
    }
    else
    {
        sign = false;
    }

    if (int(tmp) / 1000 == 0)
    {
        digitBuffer[3] = 10;
        if (sign)
        {
            digitBuffer[3] = 11;
        }
    }
    else
    {
        digitBuffer[3] = int(tmp) / 1000;
    }

    if (int(tmp) / 1000 == 0 && (int(tmp) % 1000) / 100 == 0)
    {
        digitBuffer[2] = 10;
        if (sign)
        {
            digitBuffer[2] = 11;
            digitBuffer[3] = 10;
        }
    }
    else
    {
        digitBuffer[2] = (int(tmp) % 1000) / 100;
    }

    digitBuffer[1] = (int(tmp) % 100) / 10;
    digitBuffer[0] = (int(tmp) % 100) % 10;

    delay(500);
}

```

I didn't connect thermocouple yet, but I use constant "tempC" with value = 90.8, to check if it works. If I change the value to higher - dots on displays are more dimmed.

# Answer
> -1 votes
The vendor description is not very good, however it is clear that 5 volts is not enough for these displays implying that you have to redesign the circuit to include a higher voltage power source. It does appear from the description, however, to be a common anode device. The screen shot from the data sheet shows each segment has 4 diodes in series and the DP has 2 diodes in series. That the DP lights with 5 volts indicates that the segments will light with 10 volts (possibly a bit less). Because it is common anode type you could use a TPIC6B595 shift register to replace the 74HC595. You need also 4 high side switches (each 1xPNP + 1xNPN transistor) for the 4 anodes. For this, you could also use a high side driver chip, say a MIC2981. Since the segment diode voltage drop is not shown, but should be in the range 2.1 to 4 volts, you really need to do a test to discover the optimum value of the segment current limiting resistors to give the 10mA talked about in the description, at the voltage you decide to drive the display at. The DP really requires a correspondingly higher value current limiting resistor.

---
Tags: arduino-nano, 7-segment
---


title: Motion-activated lights

text:
# Question
Title: Motion-activated lights
I am attempting to follow this tutorial to light up a dark staircase with motion-activated LED strips. If my understanding of the tutorial is correct, essentially the Arduino's job is to power or depower transistors at the appropriate time to prohibit/allow enough voltage over the LED strips on the stairs.

I have assembled a few light strips and soldered the microcontroller to the PCB with the appropriate components and was ready to test the device. The author of the guide helpfully created this video demonstrating the expected behavior of the device on start-up: the lights should blink as shown and then turn off, awaiting activation from a motion sensor. However when I try to replicate this my lights simply turn on and never turn off, fade, or blink.

Consulting the FAQ on the guide, I tried reorienting my transistors, thinking I perhaps had them backward. This had no effect.

I then tried to verify that my microprocessor was working and programmed correctly. I modified the code in the setup section, adding the following commands:

```
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
for(int i=0; i<10; i++){
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    delay(2000);
}

```

The intention was to make the built-in LED on the board blink on and off a few times during startup. While the board was connected to the computer, it indeed blinked on and off after I hit upload. When it's attached to the power supply from the PCB it does not blink (though the LED lights for the stairs turn on as I have described).

It seems to me that the microprocessor is simply not getting power or is not connected properly to the PCB. However I have done my best to verify all the connections and cannot find any problem. This is my first project of this type and am not sure what else to try. Any guidance with troubleshooting would be very much appreciated.

I apologize for the long post but I wanted to be sure to include all the necessary information. Thank you for reading!

Below are images of the PCB and schematics from the guide, which hopefully correspond to how I've actually connected the components.

Here is the code from the guide plus my blinking loop. The original is available at the author's github.

```
##Shift_Stairs.ino

#include <math.h>
#include <SPI.h>
//#include <MemoryFree.h>
//#include "expoDutyCycles.h"

//Data pin is MOSI (atmega168/328: pin 11. Mega: 51)
//Clock pin is SCK (atmega168/328: pin 13. Mega: 52)
const int ShiftPWM_latchPin=10;
const bool ShiftPWM_invertOutputs = 0; // if invertOutputs is 1, outputs will be active low. Usefull for common anode RGB led's.

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!

const int SWITCH_PIN = A0;
const int PHOTORESISTOR_PIN = A2;
const int MOTION_SENSOR_TOP_PIN = 2;
const int MOTION_SENSOR_BOTTOM_PIN = 3;

const unsigned char maxBrightness = 255;
const unsigned char pwmFrequency = 75;
const int numRegisters = 2;
const int NUMLEDs = 9;
const int MOTION_SENSOR_WARMUP_TIME = 10;
const int ON_TIME = 10000; /* The duration between turn on and turn off. */
const int LIGHT_THRESHOLD = 300; /* Anything below this sensor value will enable lights */

/* These are used to detect rising edges in the absence of interrupts.
   Using interrupts with ShiftPWM crashes the program. */
unsigned char lastReadTopPin = LOW;
unsigned char lastReadBotPin = LOW;

volatile unsigned char topActivated = false;
volatile unsigned char bottomActivated = false;
unsigned long lastMotionTime = 0;

const char BOTTOM_TO_TOP = 1;
const char TOP_TO_BOTTOM = 2;
/* For sake of the animation, stores the direction of propegation.
   Set when animation is active, cleared when animation is done.  */
char directionTriggered = 0;

const unsigned long BRIGHTNESS_SM_PERIOD = 2000; /* in μs */
unsigned long lastBrightnessSM = 0;

/* LED 0 is on the top of stairs */
unsigned char brightnesses[NUMLEDs] = {0};

void setup()   {
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    for(int i=0; i<10; i++){
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
      delay(2000);
    }
    pinMode(ShiftPWM_latchPin, OUTPUT);
    SPI.setBitOrder(LSBFIRST);
    // SPI_CLOCK_DIV2 is only a tiny bit faster in sending out the last byte.
    // SPI transfer and calculations overlap for the other bytes.
    SPI.setClockDivider(SPI_CLOCK_DIV4);
    SPI.begin();

    Serial.begin(9600);

    /* Turn on pullup resistor for switch */
    digitalWrite(SWITCH_PIN, HIGH);

    ShiftPWM.SetAmountOfRegisters(numRegisters);
    ShiftPWM.Start(pwmFrequency,maxBrightness);
    // Print information about the interrupt frequency, duration and load on your program
    ShiftPWM.SetAll(0);
    ShiftPWM.PrintInterruptLoad();
    // Fade in all outputs
    for(int j=0;j<maxBrightness;j++){
        ShiftPWM.SetAll(j);
        delay(3);
    }
    // Fade out all outputs
    for(int j=maxBrightness;j>=0;j--){
        ShiftPWM.SetAll(j);
        delay(3);
    }
}
void loop()
{
    /* Detect rising edge with polling. Interrupts crash the program. */
    unsigned char pinRead = digitalRead(MOTION_SENSOR_TOP_PIN);
    if(pinRead == HIGH && lastReadTopPin == LOW){
        topActivated = true;
    }
    lastReadTopPin = pinRead;
    /* Detect rising edge with polling. Interrupts crash the program. */
    pinRead = digitalRead(MOTION_SENSOR_BOTTOM_PIN);
    if(pinRead == HIGH && lastReadBotPin == LOW){
        bottomActivated = true;
    }
    lastReadBotPin = pinRead;

    /* Resets flags */
    if(topActivated){
        if(directionTriggered == 0){
            directionTriggered = TOP_TO_BOTTOM;
        }
        lastMotionTime = millis();
        topActivated = false;
    }
    if(bottomActivated){
        if(directionTriggered == 0){
            directionTriggered = BOTTOM_TO_TOP;
        }
        lastMotionTime = millis();
        bottomActivated = false;
    }

    /* State machine */
    if(micros() - lastBrightnessSM > BRIGHTNESS_SM_PERIOD){
        brightnessSM();
        lastBrightnessSM = micros();
    }
}
/**
    Returns true if switch is in "1" position.
*/
boolean switchPressed(){
    return !digitalRead(SWITCH_PIN);
}

```

```
###brightnessSM.ino
enum brightnessStates {
    sFullyOn,
    sOff,
    sTurningOn,
    sTurningOff,
    sOverrideSwitch
};

int brightnessState = sOff;

void brightnessSM(){
    /* Actions */
    switch(brightnessState){
    case sFullyOn:
        break;
    case sOff:
        break;
    case sTurningOn:{
        /* Increase brightness of lights. This for loop goes from -NUMLEDs to 0 or
           0 to NUMLEDs depending on the direction of propegration. */
        char startLight = -1 * (directionTriggered - 1) * (NUMLEDs - 1);
        char endLight   = -1 * (directionTriggered - 2) * (NUMLEDs - 1);
        for(char l = startLight; l <= endLight; l++){

            /* Turn on the next LED only if the ones before it
               are on*/
            if(brightnesses[abs(l)] != maxBrightness){
                brightnesses[abs(l)] += 5;
                ShiftPWM.SetOne(abs(l), brightnesses[abs(l)]);
                break;
            }

            /* Turn on the next LED only if the one before it is partially on */
//            if(brightnesses[abs(l)] != maxBrightness){
//                if(l == startLight || (brightnesses[abs(l - 1)] > maxBrightness*3/10)){
//                    brightnesses[abs(l)] += 1;
//                    ShiftPWM.SetOne(abs(l), expoDutyCycles[brightnesses[abs(l)]]);
//                }
//            }
        }
        break;
    }
    case sTurningOff:{
        /* Decrease brightness of lights. This for loop goes from -NUMLEDs to 0 or
           0 to NUMLEDs depending on the direction of propegration. */
        char startLight = -1 * (directionTriggered - 1) * (NUMLEDs - 1);
        char endLight   = -1 * (directionTriggered - 2) * (NUMLEDs - 1);
        for(char l = startLight; l <= endLight; l++){
            /* Turn on the next LED only if the ones before it
               are on*/
            if(brightnesses[abs(l)] != 0){
                brightnesses[abs(l)] -= 5;
                ShiftPWM.SetOne(abs(l), brightnesses[abs(l)]);
                break;
            }

            /* Turn on the next LED only if the one before it is partially on */
//            if(brightnesses[abs(l)] != 0){
//                if(l == startLight || (brightnesses[abs(l - 1)] < maxBrightness*9/10)){
//                    brightnesses[abs(l)] -= 1;
//                    ShiftPWM.SetOne(abs(l), expoDutyCycles[brightnesses[abs(l)]]);
//                }
//            }
        }
        break;
    }
    case sOverrideSwitch:
        break;
    }

    /* Transitions */
    switch(brightnessState){
    case sFullyOn:
        if(millis() - lastMotionTime > ON_TIME){
            brightnessState = sTurningOff;
        }
        if(switchPressed()){
            transitionToOverrideSwitch();
        }
        break;
    case sOff:
        if(directionTriggered != 0){
            if(analogRead(PHOTORESISTOR_PIN) < LIGHT_THRESHOLD){
                brightnessState = sTurningOn;
            }
            else {
                directionTriggered = 0;
            }
        }
        if(switchPressed()){
            transitionToOverrideSwitch();
        }
        break;
    case sTurningOn:{
        /* If all the lights are on then proceed */
        unsigned char allOn = true;
        for(unsigned char l = 0; l < NUMLEDs; l++){
            if(brightnesses[l] != maxBrightness){
                allOn = false;
                break;
            }
        }
        if(allOn){
            brightnessState = sFullyOn;
        }
        if(switchPressed()){
            transitionToOverrideSwitch();
        }
        break;
    }
    case sTurningOff:{
        /* If all the lights are off then proceed */
        unsigned char allOff = true;
        for(unsigned char l = 0; l < NUMLEDs; l++){
            if(brightnesses[l] != 0){
                allOff = false;
                break;
            }
        }
        if(allOff){
            directionTriggered = 0;
            brightnessState = sOff;
        }
        if(switchPressed()){
            transitionToOverrideSwitch();
        }
        break;
    }
    case sOverrideSwitch:
        if(switchPressed() == false){
            /* Switch all LEDs off */
            for(char l = 0; l < NUMLEDs; l++){
                ShiftPWM.SetOne(l, 0);
                brightnesses[l] = 0;
            }
            directionTriggered = 0;
            brightnessState = sOff;
        }
        break;
    }
}
void transitionToOverrideSwitch(){
    brightnessState = sOverrideSwitch;
    /* Switch all LEDs on */
    for(unsigned char l = 0; l < NUMLEDs; l++){
        ShiftPWM.SetOne(l, maxBrightness);
        brightnesses[l] = maxBrightness;
    }
}

```

# Answer
> 0 votes
The image of the Printed Circuit Board (PCB) posted in the above question contains many examples of what are commonly referred to as Cold Solder Joints. These types of joints are unreliable and occasionally provide no electrical connectivity. And are often impossible to visually verify. The first 2 minutes of this video demonstrate how heat and flux can be combined to remedy cold solder joints involving a PCB and feed-through pin.

*(I can edit/change the following as we narrow in on the solution for this problem. The objective is to make a good stackexchange question & answer.)*

Symptom:

* The project behaves as expected when cabled to the PC. This assumes the cable to the PC (likely to a USB/CDC to Serial Port) contains Ground, In, Out and Power. The expected behavior is to turn the LEDs on and off.
* The project does not work when disconnected from the PC and is powered by an external power supply. The LEDs only turn on.

Consider verifying power to the processor or, better, at the processor. For the problem as described in the question, there may be an interruption of the power path from the external power supply to the processor. Check all the solder joints involved in connecting the Arduino's power input to the PCB. Likely the processor (Arduino) was powered up during programming through the Ground and Power pins of the serial port cable. Once that cable was removed, the processor may not be powered and may have not been running while the PCB was only powered from an external source.

---
Tags: arduino-pro-mini, led-strip
---