[Solved] Making 'Time Variables Global'..

I have a small NNTP clock with auto TIMEZONE adjustments which runs on an ESP8266,.. I modified the code to split the different parts of the code into their own functions and files (.ino, .h), so that the code is more logically laid out.
However, since splitting I cannot globally access individual time variables for Hours or minutes etc.
I am familiar with creating variables within a function,.. and at the start to make them global or local ( to a function),.. But something beyond my knowledge is in action here.
Could someone with greater knowledge than myself explain what is going on...

Many tx....

#include "Init_and_Define.h"


void loop() {

  do {
    delay(50);
    // Do Nothing
  } while ( ( millis() - PreviousMillis ) < 1000 );
  /*
     This creates a 1 second  second timer,...
    
  */

  PreviousMillis = millis();

  getime();
  Serial.println("Hello World");
  delay(1000);
  t += second(local);                           THIS CAUSES COMPILE FAILURES
  Serial.println(t);                                WITH:-  error: 'local' was not declared in this scope

}

clockfunc.ino

void getime() {
  if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
  {
    date = "";  // clear the variables
    t = "";

    // update the NTP client and get the UNIX UTC timestamp
    timeClient.update();
    epochTime =  timeClient.getEpochTime();

    // convert received time stamp to time_t object
    time_t local, utc;
    utc = epochTime;

    // Then convert the UTC UNIX timestamp to local time
    TimeChangeRule ukBST = {"BST", Last, Sun, Mar, 1, 60};  //
    TimeChangeRule ukGMT = {"GMT", Last, Sun, Oct, 2, 0};   //
    Timezone ukLondon(ukBST, ukGMT);
    local = ukLondon.toLocal(utc);

    // now format the Time variables into strings with proper names for month, day etc
    date += days[weekday(local) - 1];
    date += ", ";
    date += months[month(local) - 1];
    date += " ";
    date += day(local);
    date += ", ";
    date += year(local);

    // format the time to 12-hour format with AM/PM and no seconds
    if (hour(local) < 10) // add a zero if minute is under 10
      t += "0";
    t += hour(local);
    t += ":";
    if (minute(local) < 10) // add a zero if minute is under 10
      t += "0";
    t += minute(local);
    t += ":";
    if (second(local) < 10) // add a zero if minute is under 10
      t += "0";
    t += second(local);
    //    t += " ";
    //    t += ampm[isPM(local)];

    // Display the date and time
    snprintf(TimeDateSTR, BUFF_MAX, "%s %d %s %02d:%02d",
             days[weekday(local) - 1], day(local), months[month(local) - 1],  hour(local), minute(local)   );

    Serial.println(TimeDateSTR);

    Serial.println(date);
    Serial.println(t);

  }
  else // attempt to connect to wifi again if disconnected
  {

    delay(1000);
  }
}

// --------------------------------------

Setup.ino

void setup() {

  Serial.begin(57600);
  delay(10);

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());


  timeClient.begin();   // Start the NTP UDP client


  Serial.println("\nWaiting for time");

  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println("Got Time OK");


}

Init_and_Define.h

#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <time.h>                       // time() ctime()
#include <sys/time.h>                   // struct timeval
#include <coredecls.h>                  // settimeofday_cb()

#include <string.h>
#include <WifiUDP.h>
#include <NTPClient.h>
#include <Time.h>
#include <TimeLib.h>
#include <Timezone.h>

const char* ssid     = "somethn";                   // wifi ssid
const char* password = "fhlkfjhlkjgfl";                 // wifi password

String auth          = "bWFya0BoYJLS1hHVQ==";
// Authentication credentials Create a string from <email_address>:<API_Password> and encode it base64
// The sample: https://www.base64encode.org/
//    String auth = "dXNlcjpzd29yZA=="
// is the encoding for "user:password" 567rujhdgfjh5

const char* host      = "www.ic2pro.com";
const int   httpPort  = 80;
String devId          = "dc79761b-33fd5f";
// Device ID. CREATE YOUR OWN GUID; Use this http://www.guidgenerator.com/



#define Chk_Bit(var,pos) (((var)>>(pos)) & 1)

#define Set_Bit(var,pos) ((var) |= (1<<(pos)))

#define Clr_Bit(var,pos) ((var) &=  ~(1<<(pos)))

#define Tog_Bit(var,pos) ((var) ^= (1<<(pos)))


byte BitTestFlags = 0;    // Initialise flags to all zero and cleared
//        Name          Bit No.
#define TempTooHigh     0  // Temperature to High
#define LastReadCore    1  // Time between probe reads too long
#define LastReadDoor    2
#define LastReadRad     3
#define LastReadExtrn   4
#define OneShotTimer    5
#define RDInProgress    6   // Flag Set if Read in Progress
#define WRInProgress    7   // Flag set if Write in progress


#define LEDoutput      D7   // Set Output pin for LED
#define FANoutput      D3   // Set Output pin for FAN
#define BUFF_MAX 32

// Define NTP properties
#define NTP_OFFSET   0      // In seconds
#define NTP_INTERVAL 60 * 1000    // In miliseconds
#define NTP_ADDRESS  "0.uk.pool.ntp.org"  // change this to whatever pool is closest (see ntp.org)

// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

String date;
String t;
const char * days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} ;
const char * months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
const char * ampm[] = {"AM", "PM"} ;

unsigned long currentMillis, PreviousMillis = millis(), time_now = 0,  epochTime;

char TimeDateSTR[BUFF_MAX];
  do {
    delay(50);
    // Do Nothing
  } while ( ( millis() - PreviousMillis ) < 1000 );

delay(50) is NOT doing nothing.

The IDE is making one cpp file from your ino files, placing the contents of the ino files, in alphabetical order, in the cpp file. Without knowing the names of ALL of the files, we can't determine the order of the code in the cpp file, but, perhaps you can.

Variable should not be defined in .h files, they should only be declared. If you don't know the difference, check out:

Also, since you're (wisely) going the route of using multiple files to modularize your code, don't do it the brain-dead Arduino way of having multiple .ino files. They end up being simply mashed together before compilation and you lose the benefit of separating them. The best way (IMO) is to use proper .cpp and .h files as done by programmers who do it for a living. Check out my Reply #3 in this thread.

#define NTP_INTERVAL 60 * 1000    // In miliseconds

That looks like a bug waiting to happen.

Wow Tx guys,.. yes,.. I knew less than I thought.....
Thankyou for the pointer On my incorrect delay,... so Is my code correct ,.. for creating some 'none blocking code', that creates a delay by simply removing the 'delay(); statement?

As for the file names they are simply as follows:-
MotionSenseV0.11.ino
clockfunc.ino
CloudAccess.ino
Init_and_Define.h
Setup.ino

Even if the files a concatenated together,.. I did not appreciate this but I understand the mechanism,... How does this affect how I can call the time variables for minutes etc.

minute(local),.. and then not being 'seen' outside of the getime() function found in the clockfunc.ino file ...

'#define NTP_INTERVAL 60 * 1000 // In miliseconds

As you comment this is poor programming,.. I will modify to just '60000',.. to avoid any ambiguity at the compile stage. I assume this can lead to strange things when the substitutions are made.

Many thx for your comments.

The way the concatenation happens is all .ino files are concatenated into a single file. This is done in the order the tabs are shown in the Arduino IDE. The first file is the one that matches your sketch folder name. After that, they are added in alphabetical order. Note that this is only done for .ino files.

So you need to make sure that your declarations of global variables are made in the file above the first time the variable is referenced in your code.

Ah so that starts to make sense,..
So How do I reorder the TABs...? I only seem to able to do that by creating the names,.. eg 00_nameone.ino
etc.
Although by forcing the Main file,.. followed by the declare and declaration second,.. followed by setup.ino,... followed by everything else... does not seem to fix my problems.. that time variables are not globally accessible..

When I enter the following code into the Main Loop.

t += second(local);
Serial.print(t);
I get the following error:-

03_MotionSenseV2.11:26:17: error: 'local' was not declared in this scope

t += second(local);

^

exit status 1
'local' was not declared in this scope

Any more thoughts from anyone,.. as I am at the limits of my knowledge/understanding..
Rgds and tx

I don't see the name 'local' defined anywhere. Where was it defined?

diyhouse:
So How do I reorder the TABs...? I only seem to able to do that by creating the names,.. eg 00_nameone.ino

That's the way to do it. The tab ordering and concatenation is both done on the basis of alphabetical sorting. Even if you were to hack the Arduino IDE to show the tabs in a different order, it would have no effect on the concatenation order, which is not based on tab order.

The esp8266 core includes NTP support and POSIX compliant time library functions that do all the timezone and DST adjustments.
You just give it the NTP server(s) using configTime() and set the TZ variable to a POSIX compliant timezone string using setenv() and tzset()
After that you can use the all normal time functions:
gettimeofday(), clock_gettime(), time(), ctime(), asctime(), gmtime(), localtime() etc...

the NTP updates will happen in the background and the timezone offset and DST adjustments will be done according to the TZ string.

--- bill

bperrybap:
The esp8266 core includes NTP support and POSIX compliant time library functions that do all the timezone and DST adjustments.

Interesting. I've used NTP in conjunction with the standard Arduino time.h library on ESP, but wasn't aware there's something more "built-in". Hunted around my installation and found the "NTP-TZ-DST.ino" example. That led me to the ESP-specific time library. Looking at its source code now.

So, calls to the NTP server happen in the background? Can you specify how often that happens?

So, calls to the NTP server happen in the background? Can you specify how often that happens?

// Define NTP properties
#define NTP_OFFSET   0      // In seconds
#define NTP_INTERVAL 60000    // In miliseconds
#define NTP_ADDRESS  "0.uk.pool.ntp.org"  // change this to whatever pool is closest (see ntp.org)

// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

This is where the original code came from that I hacked around with....

Which looks like this,... but this was just a single flat file, in moving the functions to their own file I cannot access time/date variables globally within other routines...

// simplestesp8266clock.ino
//
// Libraries needed:
//  Time.h & TimeLib.h:  https://github.com/PaulStoffregen/Time
//  Timezone.h: https://github.com/JChristensen/Timezone
//  SSD1306.h & SSD1306Wire.h:  https://github.com/squix78/esp8266-oled-ssd1306
//  NTPClient.h: https://github.com/arduino-libraries/NTPClient
//  ESP8266WiFi.h & WifiUDP.h: https://github.com/ekstrand/ESP8266wifi
//
// 128x64 OLED pinout:
// GND goes to ground
// Vin goes to 3.3V
// Data to I2C SDA (GPIO 0)
// Clk to I2C SCL (GPIO 2)

#include <ESP8266WiFi.h>
#include <WifiUDP.h>
#include <String.h>
#include <Wire.h>
#include <SSD1306.h>
#include <SSD1306Wire.h>
#include <NTPClient.h>
#include <Time.h>
#include <TimeLib.h>
#include <Timezone.h>

// Define NTP properties
#define NTP_OFFSET   60 * 60      // In seconds
#define NTP_INTERVAL 60 * 1000    // In miliseconds
#define NTP_ADDRESS  "ca.pool.ntp.org"  // change this to whatever pool is closest (see ntp.org)

// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

// Create a display object
SSD1306  display(0x3d, 0, 2); //0x3d for the Adafruit 1.3" OLED, 0x3C being the usual address of the OLED
 
const char* ssid = "*************************";   // insert your own ssid 
const char* password = "**********";              // and password
String date;
String t;
const char * days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"} ;
const char * months[] = {"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
const char * ampm[] = {"AM", "PM"} ;
 
void setup () 
{
  Serial.begin(115200); // most ESP-01's use 115200 but this could vary
  timeClient.begin();   // Start the NTP UDP client

  Wire.pins(0, 2);  // Start the OLED with GPIO 0 and 2 on ESP-01
  Wire.begin(0, 2); // 0=sda, 2=scl
  display.init();
  display.flipScreenVertically();   

  // Connect to wifi
  Serial.println("");
  Serial.print("Connecting to ");
  Serial.print(ssid);
  display.drawString(0, 10, "Connecting to Wifi...");
  display.display();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi at ");
  Serial.print(WiFi.localIP());
  Serial.println("");
  display.drawString(0, 24, "Connected.");
  display.display();
  delay(1000);
}

void loop() 
{
  if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
  {   
    date = "";  // clear the variables
    t = "";
    
    // update the NTP client and get the UNIX UTC timestamp 
    timeClient.update();
    unsigned long epochTime =  timeClient.getEpochTime();

    // convert received time stamp to time_t object
    time_t local, utc;
    utc = epochTime;

    // Then convert the UTC UNIX timestamp to local time
    TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -300};  //UTC - 5 hours - change this as needed
    TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -360};   //UTC - 6 hours - change this as needed
    Timezone usEastern(usEDT, usEST);
    local = usEastern.toLocal(utc);

    // now format the Time variables into strings with proper names for month, day etc
    date += days[weekday(local)-1];
    date += ", ";
    date += months[month(local)-1];
    date += " ";
    date += day(local);
    date += ", ";
    date += year(local);

    // format the time to 12-hour format with AM/PM and no seconds
    t += hourFormat12(local);
    t += ":";
    if(minute(local) < 10)  // add a zero if minute is under 10
      t += "0";
    t += minute(local);
    t += " ";
    t += ampm[isPM(local)];

    // Display the date and time
    Serial.println("");
    Serial.print("Local date: ");
    Serial.print(date);
    Serial.println("");
    Serial.print("Local time: ");
    Serial.print(t);

    // print the date and time on the OLED
    display.clear();
    display.setTextAlignment(TEXT_ALIGN_CENTER);
    display.setFont(ArialMT_Plain_24);
    display.drawStringMaxWidth(64, 10, 128, t);
    display.setFont(ArialMT_Plain_10);
    display.drawStringMaxWidth(64, 38, 128, date);
    display.display();
  }
  else // attempt to connect to wifi again if disconnected
  {
    display.clear();
    display.drawString(0, 10, "Connecting to Wifi...");
    display.display();
    WiFi.begin(ssid, password);
    display.drawString(0, 24, "Connected.");
    display.display();
    delay(1000);
  }
    
  delay(10000);    //Send a request to update every 10 sec (= 10,000 ms)
}

diyhouse:

// Define NTP properties

#define NTP_OFFSET   0      // In seconds
#define NTP_INTERVAL 60000    // In miliseconds
#define NTP_ADDRESS  "0.uk.pool.ntp.org"  // change this to whatever pool is closest (see ntp.org)

// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

Yes, but that's using an extra NTPClient library. I was asking about the ESP core's "built-in" NTP functionality.

diyhouse:
This is where the original code came from that I hacked around with....

https://www.instructables.com/id/Simplest-ESP8266-Local-Time-Internet-Clock-With-OL/
Which looks like this,... but this was just a single flat file, in moving the functions to their own file I cannot access time/date variables globally within other routines...

I'd be willing to bet it has to do with the order that .ino files are mashed together before being compiled (as has already been mentioned). One of the reasons I referred to the "Arduino Method" of multiple tabs / files as brain-dead.

If it were my project, I'd use the technique that I linked back in Reply #2.

gfvalvo:
Yes, but that's using an extra NTPClient library. I was asking about the ESP core's "built-in" NTP functionality.

See this post for an example of how to use the built in NTP stuff.

Note that there are some issues with the NTP integration.
This issue outlines the problem: Serious issues with timezone support in time functions · Issue #4637 · esp8266/Arduino · GitHub
The summary is they totally screwed up the implementation by not understanding how the timezones and offsets is supposed to work and now I don't think they want to go back and fix it to work correctly for fear of breaking something - even though the current offset implementation breaks most of the API functions.
All that said, it is still very usable if you just avoid using the offset stuff.
Just set your ntp server(s), and your TZ variable as shown in the example code I provided and it should work.

In terms of how often the background NTP code syncs, it looks like it is fixed at once per hour. There should be a call called sntp_update_delay() that should allow you to set the sync interval; HOWEVER, they didn't include that function in the Arduino version of the library.
See this issue: Can't set sntp_update_delay · Issue #5938 · esp8266/Arduino · GitHub
If you really need it more often that than that the only way I know of doing it is to trick the code into syncing by stopping and re-starting ntp.

Other than that it is really simple to use and works great as it provides a unix time library API, which has existed for nearly 50 years, much longer than all the late comers and OSes that tried to re-invent the world over the past few decades.

If you use the Wifi Manager you can add FS parameters to allow the user to set the TZ string so that nothing is hard coded.

--- bill

OK,.. Some great discussions on NTP stuff,...
I have renamed my files,...as follows:-

01_MotionSenseV2.11.h this is actually the header file,.. the define and declares..
02_Setup.ino
03_Main.ino this is where the Main Loop starts
05_clockfunc.ino
12_CloudAccess.ino

Cannot start Arduino IDE with .h files,.. must start IDE with and .ino file..

these all failed..... so I copied the contents of the define and declares stuff to the top of main, followed by the contents of the setup.ino...

All these variations still failed to compile the minute(local) statements with:-

'local' was not declared in this scope

Please attach all your files to a reply here so we can take a look. We also need to know what the name of your sketch folder is. If you click the "Reply" button, you will see an "Attachments and other settings" link that will allow you to make the attachments.

many tx for reviewing..

Files all stored in a folder called 'Motion_senseV1.99'

01_Init_and_Define.h (2.83 KB)

02_Setup.ino (831 Bytes)

05_clockfunc.ino (1.79 KB)

12_CloudAccess.ino (2.02 KB)

Motion_senseV1.99.ino (1.43 KB)