ESP32Time.h needlessly repetetive recursive redundancy

I tried to make ESP32Time set my T Beam clock from the GPS. The GPS works. The compiler tells me that the scope was not declared to run setTime() despite ESP32.h library being included in the program

I tried to do an end run around that by lifting the necessary code from the library and dropping it in my code. I discovered this pearl of information:

void setTime(int sc, int mn, int hr, int dy, int mt, int yr) //const
{
  // seconds, minute, hour, day, month, year $ microseconds(optional)
  // ie setTime(20, 34, 8, 1, 4, 2021) = 8:34:20 1/4/2021
  struct tm t = {0, 0, 0, 0, 0, 0, 0, 0, 0};      // Initalize to all 0's
  t.tm_year = yr - 1900;    // This is year-1900, so 125 = 2025
  t.tm_mon = mt - 1;
  t.tm_mday = dy;
  t.tm_hour = hr;
  t.tm_min = mn;
  t.tm_sec = sc;
  time_t timeSinceEpoch = mktime(&t);
  setTime(timeSinceEpoch);
}

note that the last line calls the function again, and setTime(timeSinceEpoch) requires a 32 bit integer. the compiler squawks about “too few arguments to function ‘void setTime(int, int, int, int, int, int)’

I can’t believe I am the first person to encounter this. I had to // that const because that also caused a failure to compile..

the entire code:

// T Beam Lora Gateway for FSBs 009H port /dev/ttyACMO 20250827
// TTD: MOUNT ALL, RTC_INT, TEST_PIN, GPS set time,
// add counters to bail on invalid GPS or LoRa
// dateUpdate(), setTimezone

#include "soc/soc.h"           // Disable brownout problems
#include "soc/rtc_cntl_reg.h"  // Disable brownout problems
#include <WiFi.h>
#include <Wire.h>
#include <SPI.h>
#include <FS.h>
#include <SD.h>
#include <LoRa.h>  // Sandeepmistry
//#include <timeLib.h>
#include <ESP32Time.h>
#include <time.h>  // ESP32Time
#include <TinyGPS++.h>
#include <HardwareSerial.h>
#include "RTClib.h"
RTC_DS3231 rtc;
#define RTC_INT_PIN 36  // the pin that is connected to SQW on the RTC
#define TEST_PIN 38     // middle pushbutton as system test
volatile bool setFSBtime;

byte FSBID = 0;         // ID of the receiver

SPIClass* vspi = NULL;              // VSPI LoRa
SPIClass* hspi = NULL;              // HSPI SD
File dataFile;                      // filename variable for SD
char filename[] = "00000000.CSV";   // filename array for datalogger
char logString[] = "000000000000";  // string for the event log; may be one char too long.
#define HAS_SDCARD 1
#define SDCARD_MISO 04  // RED 02
#define SDCARD_CS 13    // YLO 13
#define SDCARD_SCLK 14  // ORG 14
#define SDCARD_MOSI 15  // YLO 15

bool getFilenameStatus = true;

#define I2C_SDA 21   // GRA 21
#define I2C_SCL 22   // VIO 22

#define ss   18      // VSPI CLK
#define rst  23      // VSPI MOSI
#define dio0 26      // LoRA IO

#define BAND 915E6   // 915E6 for North America

HardwareSerial GPSSerial(2);
#define GPS_RX_PIN 34
#define GPS_TX_PIN 12
TinyGPSPlus gps;

HardwareSerial SoundSerial(1);  // YX-5300
#define Sound_RX_PIN -1         // Not required
#define Sound_TX_PIN 25         // WHT TO YX-5300 RX
int sw = 0;
#define CMD_SEL_DEV 0X09
#define DEV_TF 0X02
#define CMD_SET_VOLUME 0X06
#define CMD_PLAY_W_INDEX 0X03
#define CMD_PLAY_FOLDER_FILE 0X0f         // 0x7E 06 0F 00 01 02 EF;( play folder 01/002.wav )
static unsigned int Send_buf[8] = { 0 };  //      char string for YX-5300 commands
int folderArray[]         = {  0,  1,  2,  3,  4,  5,  5,  5,  6,  6,  6,  6,  12,  13,  14,};
int filesPerFolderArray[] = {  15, 20, 30, 4,  6,  9,  9,  9,  25, 25, 25, 25, 29,  255, 74,};

/////////////////////////// Set these to suit your system and location /////////////////////

String hostname = "T Beam Gateway 09H3]";
const char* ssid = "ad5mb";            // "yourNetworkName";
const char* password = "sansuiau517";  // "yourNetworkPassword";
const char* ntpServer = "us.pool.ntp.org";
const char* timezone = "MST7MDT,M3.2.0,M11.1.0";  // https://leo.leung.xyz/wiki/Timezone

int localElevation = 1421;  // elevation in meters

/////////////////////////////////////////////////////////////////////////////////////////

struct tm timeinfo;
int    counter = 0;  // Initialize variables to get and save LoRa    data
int    LoRarssi = 0;
float  temperature_C;  // Initialize variables to get and save Weather data
float  temperature_F;
float  pressure_hPa;
float  Pressure;
float  pressure_inHg;
float  Humidity;
float  seaLevelPressure_hPa;
float  seaLevelPressure_inHg;
float  dewpoint_F;
float  dewpoint_C;
String fsbid;
String loRaMessage;
String alarmStatus;
String temperature;
String pressure;
String humidity;
String readingID;

//////////////////////////////////// RUN ONCE //////////////////////////////////////

void initWiFi() 
{
  WiFi.mode(WIFI_STA);
  WiFi.setHostname(hostname.c_str());  // define hostname

  Serial.print("WiFi Scan start ");
  int n = WiFi.scanNetworks();
  Serial.print("WiFi Scan done ");
  if (n == 0) 
  {
    Serial.println("no networks found");
  } else 
  {
    Serial.print(n);
    Serial.println(" networks found");
    Serial.println(" # | SSID                             | RSSI | CH | Encryption");
    for (int i = 0; i < n; ++i) {
      Serial.printf("%2d", i + 1);
      Serial.print(" | ");
      Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
      Serial.print(" | ");
      Serial.printf("%4d", WiFi.RSSI(i));
      Serial.print(" | ");
      Serial.printf("%2d", WiFi.channel(i));
      Serial.print(" | ");
      switch (WiFi.encryptionType(i)) 
      {
        case WIFI_AUTH_OPEN:
          Serial.print("open");
          break;
        case WIFI_AUTH_WEP:
          Serial.print("WEP");
          break;
        case WIFI_AUTH_WPA_PSK:
          Serial.print("WPA");
          break;
        case WIFI_AUTH_WPA2_PSK:
          Serial.print("WPA2");
          break;
        case WIFI_AUTH_WPA_WPA2_PSK:
          Serial.print("WPA+WPA2");
          break;
        case WIFI_AUTH_WPA2_ENTERPRISE:
          Serial.print("WPA2-EAP");
          break;
        default:
          Serial.print("unknown");
      }
      Serial.println();
      delay(10);
    }
    WiFi.scanDelete();
    Serial.println();
  }

  /////////////////////////////////////////////////////////////////////////

  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.println(":");
  while (!WiFi.begin(ssid, password));
  {
    counter++;
    Serial.print("WiFiv ");
    Serial.print(counter);
    Serial.print(F(" "));
    delay(1000);
    if (counter == 10) 
    {
      counter = 0;
      Serial.println();
      Serial.print("WiFi AP ");
      Serial.print(ssid);
      Serial.println(" not available ");
      return;
    }
    Serial.println();
  }
}

void WiFiStationGotIP(WiFiEvent_t event, WiFiEventInfo_t info) 
{
  Serial.print("WiFiStationGotIP: ");
  Serial.println(IPAddress(info.got_ip.ip_info.ip.addr));
  return;
}

void initTime(String timezone)  // stable
{
  if (WiFi.status() == WL_CONNECTED) 
  {
    Serial.println("initTime getting NTP time: ");
    while (!getLocalTime(&timeinfo) && counter < 10) {
      configTime(0, 0, ntpServer);  // connect to NTP server, with 0 TZ offset
      counter++;
      Serial.print("NTPv ");
      Serial.print(counter);
      Serial.print(F(" "));
    }
    Serial.println();
    if (getLocalTime(&timeinfo)) 
    {
      setTimezone(timezone);
      Serial.print("LocalTime: ");
      printLocalTime();
    }
  } else if (!getLocalTime(&timeinfo)) 
  {
    Serial.println("NTPv: readParseGPS");
    Serial.println();
    readParseGPS();
  }
}

void setTimezone(String timezone)  // stable
{
  Serial.printf("Setting Timezone to %s\n", timezone.c_str());
  setenv("TZ", timezone.c_str(), 1);  // adjust the TZ. Clock settings are adjusted to show the new local time
  tzset();
  return;
}

void startLoRA()  // stable 1 day = 86,400,000 milliseconds
{
  LoRa.setPins(ss, rst, dio0);  // Initialize LoRa transceiver module
  while (!LoRa.begin(BAND) && counter < 10) 
  {
    Serial.print("LoRav ");
    counter++;
    delay(500);
  }
  if (counter == 10) 
  {
    counter = 0;
    Serial.print("LoRav ");
    Serial.println();
  } else {
    Serial.println("LoRa^");
    Serial.println();
  }
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> CALLED FUNCTIONS  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//

void setRTC() 
{
  Serial.print("setRTC(); ");
  getLocalTime(&timeinfo);
  rtc.adjust(DateTime(timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
                      timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec));
  DateTime now = rtc.now();
  Serial.print("RTC set to: ");
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print('/');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
}  Serial.println();

void printLocalTime()  // stable
{
  if (!getLocalTime(&timeinfo)) 
  {
    Serial.println("Failed to obtain NTP time");
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S Timezone %Z %z ");  // Friday, April 15 2022 19:18:51 zone MDT -0600
  Serial.println();
}

void readParseGPS() 
{
  if (GPSSerial.available()) 
  {
    while (GPSSerial.available() > 0)
      gps.encode(GPSSerial.read());
  }
  if (gps.date.isUpdated()) 
  {
    Serial.print(F("GPS Year="));
    Serial.print(gps.date.year());
    Serial.print(F(" "));
    Serial.print(F("GPS Month="));
    Serial.print(gps.date.month());
    Serial.print(F(" "));
    Serial.print(F("GPS Day="));
    Serial.println(gps.date.day());
  }
  if (gps.time.isUpdated()) 
  {
    Serial.print(F("Hour="));
    Serial.print(gps.time.hour());
    Serial.print(F(" "));
    Serial.print(F("Minute="));
    Serial.print(gps.time.minute());
    Serial.print(F(" "));
    Serial.print(F("Second="));
    Serial.println(gps.time.second());
    setTime(gps.time.second(),gps.time.minute(), gps.time.hour(), gps.date.day(), gps.date.month(), gps.date.year());
  }
}

void setTime(int sc, int mn, int hr, int dy, int mt, int yr) //const
{
  // seconds, minute, hour, day, month, year $ microseconds(optional)
  // ie setTime(20, 34, 8, 1, 4, 2021) = 8:34:20 1/4/2021
  struct tm t = {0, 0, 0, 0, 0, 0, 0, 0, 0};      // Initalize to all 0's
  t.tm_year = yr - 1900;    // This is year-1900, so 125 = 2025
  t.tm_mon = mt - 1;
  t.tm_mday = dy;
  t.tm_hour = hr;
  t.tm_min = mn;
  t.tm_sec = sc;
  time_t timeSinceEpoch = mktime(&t);
  setTime(timeSinceEpoch);
}

//void IRAM_ATTR testPinSet()
//{
//  sw = (6);  = (1); //random(1, 15);
//}

void setRemotetime() 
{
  setFSBtime = true;  // isr for midnight alarm
}

void dateUpdate()  // Midnight FSB time Update
{
  if (setFSBtime == true) 
  {
    setFSBtime = false;
    rtc.clearAlarm(1);
  }
  if (gps.time.isValid())  // first couple of times through the loop, gps not yet available
  {
    LoRa.beginPacket();  // send LoRa packet
    LoRa.printf("Time: %.2d:%.2d:%.2d\n", gps.time.second(), gps.time.minute(), gps.time.hour());
    LoRa.endPacket();
    Serial.println("FSBs set to GPS time");
    Serial.println("Midnight FSB time Update^ Alarm(1) cleared. setFSB time cleared");
  }
}

////////////////////////////////////////////////////////////////////////////////////

void readParseLoRa()  // Read LoRa packet and get the sensor readings
{
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    Serial.print("Lora packet received: ");
    Serial.print(packetSize);
    Serial.println(" characters");
    while (LoRa.available())  // Read packet
    {
      String LoRaData = LoRa.readString();
      Serial.print(LoRaData);
      int pos1 = LoRaData.indexOf('@');
      int pos2 = LoRaData.indexOf('/');
      int pos3 = LoRaData.indexOf('!');
      int pos4 = LoRaData.indexOf('F');
      int pos5 = LoRaData.indexOf('P');
      int pos6 = LoRaData.indexOf('%');
      fsbid = LoRaData.substring(0, pos1);                         // Get FSB ID
      readingID = LoRaData.substring(pos1 + 1, pos2);              // Get readingID
      alarmStatus = LoRaData.substring(pos2 + 1, pos3);            // Get alarmStatus
      temperature = LoRaData.substring(pos3 + 1, pos4);            // Get temperature
      pressure = LoRaData.substring(pos4 + 1, pos5);               // Get pressure
      humidity = LoRaData.substring(pos5 + 1, LoRaData.length());  // Get humidity
    }

    LoRarssi = LoRa.packetRssi();  // Get RSSI
    Serial.print(" LoRa RSSI: ");
    Serial.println(LoRarssi);
    Serial.print("alarmStatus = ");
    Serial.print(alarmStatus);
    Serial.print(" alarmStatus.toInt() = ");
    Serial.println(alarmStatus.toInt());
    Serial.println();

    if (alarmStatus.toInt() != 0) 
    {
      Serial.print("Alarm Triggered > ");
      Serial.print(alarmStatus);
      Serial.print(F(" "));
      int sw = alarmStatus.toInt();
      Serial.print("sw = ");
      Serial.println(sw);
      Serial.println();
      alarmHandler(sw);
    }
    BME_280_conversions();
  }
}

////////////////////////////////////////////////////////////////////////////////////

void alarmHandler(int sw) 
{
  logEvent();   // log event to SD card
  playWAV(sw);  // play appropriate sound file
}

void getFilename()  //
{
  if (getFilenameStatus == true) 
  {
    getLocalTime(&timeinfo);
    sprintf(filename, "%04d%02d%02d", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
    Serial.print("filename(): ");
    Serial.println(filename);
    Serial.println();
    getFilenameStatus = false;
  }
}

void logEvent() 
{
  getLocalTime(&timeinfo);
  {
    File dataFile = SD.open(filename, FILE_WRITE);
    if (dataFile)  // if the file is available, write to it:
    {
      sprintf(logString, "%02d,%02d,%02d,%02d", FSBID, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
      dataFile.println(logString);
      dataFile.close();
      Serial.print("Event log string saved: ");
      Serial.println(logString);
    }
  }
}

////////////////////////////////////
// YX5300 sound module functions ///
////////////////////////////////////

void playWAV(int sw) 
{
  int folder = folderArray[sw];
  int filesPerFolder = filesPerFolderArray[sw];
  randomFile(folder, filesPerFolder);
}

void randomFile(int folder, int filesPerFolder) 
{
  randomSeed(timeinfo.tm_sec);
  sendCommand(CMD_PLAY_FOLDER_FILE, 0x0F0000 + (folder * 256) + (random(1, filesPerFolder)));
}

void sendCommand(uint8_t command, int16_t dat) 
{
  Send_buf[0] = 0x7e;                // starting byte
  Send_buf[1] = 0xff;                // version
  Send_buf[2] = 0x06;                // the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command;             //
  Send_buf[4] = 0x00;                // 0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = (int8_t)(dat >> 8);  // data high byte
  Send_buf[6] = (int8_t)(dat);       // data low byte
  Send_buf[7] = 0xef;                // ending byte
  for (uint8_t i = 0; i < 8; i++) 
  {
    SoundSerial.write(Send_buf[i]);
    Serial.print(Send_buf[i], HEX);
  }
  Serial.println();
}

void BME_280_conversions() 
{
  temperature_C = (temperature.toInt());
  Serial.print("Temperature C = ");
  Serial.print(temperature_C);
  Serial.println(" *C");
  temperature_F = ((1.8 * temperature_C) + 32);  // Convert Celcius temperature to Fahrenheit
  Serial.print("Temperature F = ");
  Serial.print(temperature_F);
  Serial.println(" F");
  Pressure = (pressure.toInt());
  pressure_hPa = ((Pressure / 100.0F));
  Serial.print("Pressure hPa  = ");
  Serial.print(pressure_hPa);
  Serial.println("  hPa");
  pressure_inHg = ((pressure_hPa / 100.0F) / 33.864);  // Convert hectoPascals to inHg
  Serial.print("Pressure inHG = ");
  Serial.print(pressure_inHg);
  Serial.println(" inHG");
  Humidity = (humidity.toInt());
  Serial.print("Humidity      = ");
  Serial.print(Humidity);
  Serial.println(" %");
  seaLevelPressure_hPa = pressure_hPa / pow(1.0 - 0.0065 * localElevation / (temperature_C + 273.15), 5.255);
  Serial.print("Sea Level Pressure hPa  = ");
  Serial.print(seaLevelPressure_hPa);
  Serial.println(" hPa");
  seaLevelPressure_inHg = seaLevelPressure_hPa / 33.864;
  Serial.print("Sea Level Pressure inHg = ");
  Serial.print(seaLevelPressure_inHg);
  Serial.println(" inHg");
  dewpoint_F = 243.04 * (log(Humidity / 100) + ((17.625 * temperature_F) / (243.04 + temperature_F))) / (17.625 - log(Humidity / 100) - ((17.625 * temperature_F) / (243.04 + temperature_F)));
  Serial.print("Dewpoint = ");
  Serial.print(dewpoint_F);
  Serial.println(" F");
  dewpoint_C = ((temperature_F - 32) / 1.8);  // Convert Fahrenheit temperature to Celcius
  Serial.print("Dewpoint = ");
  Serial.print(dewpoint_C);
  Serial.println(" C");
  Serial.println();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() 
{
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);  //disable brownout detector
  Serial.begin(115200);
  Serial.println();
  Serial.println("T Beam Gateway V009H");  // current status

  //  pinMode(TEST_PIN, INPUT);
  //  attachInterrupt(digitalPinToInterrupt(TEST_PIN), testPinSet, FALLING);

  GPSSerial.begin(9600, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
  pinMode(GPS_TX_PIN, OUTPUT);  // TO   GPS RX
  pinMode(GPS_RX_PIN, INPUT);   // FROM GPS TX

  SoundSerial.begin(9600, SERIAL_8N1, Sound_RX_PIN, Sound_TX_PIN);
  pinMode(Sound_TX_PIN, OUTPUT);     // TO   YX-5300 RX
  sendCommand(CMD_SEL_DEV, DEV_TF);  // Select the YX-5300 TF card
  delay(200);
  sendCommand(CMD_SET_VOLUME, 0x06001e);  // set volume to mid range
  delay(200);
  randomSeed(timeinfo.tm_sec);
  sendCommand(CMD_PLAY_W_INDEX, 0x030000 + random(1, 15));  // play on reset 1 of 15 files in TF card root
  Serial.println();

  vspi = new SPIClass(VSPI);
  vspi->begin(SCK, MISO, MOSI, SS);  // LoRa SPI
  //loRa_SCLK 5 loRa_MISO 19 loRa_MOSI 27 loRa_SS 18
  pinMode(SS, OUTPUT);
  pinMode(SCK, OUTPUT);
  pinMode(MOSI, OUTPUT);
  pinMode(MISO, INPUT);

  hspi = new SPIClass(HSPI);
  pinMode(SDCARD_CS, OUTPUT);
  hspi->begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_CS);
  //SDCARD_SCLK 14 SDCARD_MISO 02 SDCARD_MOSI 15 SDCARD_CS 13

  if (!SD.begin(SDCARD_CS)) 
  {
    Serial.println("SDv ");
    Serial.println();
  }

  if (SD.begin()) 
  {
    Serial.println("SD^ ");
    Serial.println();
    uint32_t cardSize = SD.cardSize() / (1024 * 1024);
    char outputString[2];
    itoa(cardSize, outputString, 10);
    Serial.print("Card Size = ^ ");
    Serial.print(cardSize);
    Serial.print(" mb ");
  }

  Wire.begin(I2C_SCL, I2C_SDA);
  Serial.println("I2C scanner. Scanning ...");
  byte count = 0;
  for (byte i = 8; i < 120; i++) 
  {
    Wire.beginTransmission(i);
    if (Wire.endTransmission() == 0) 
    {
      Serial.print("Found address: ");
      Serial.print(i, DEC);
      Serial.print(" (0x");
      Serial.print(i, HEX);
      Serial.println(")");
      count++;
      delay(1);
    }  // end of good response
  }    // end of for loop
  Serial.print("Done.");
  Serial.print("Found ");
  Serial.print(count, DEC);
  Serial.println(" device(s).");
  Serial.println();

  if (!rtc.begin()) 
  {
    Serial.println("RTCv");
    Serial.println();
  } else if (rtc.begin()) {
    Serial.println("rtc.begin");
    rtc.disable32K();             // disable the 32K Pin
    pinMode(RTC_INT_PIN, INPUT);  // attach an interrupt to the alarm
    attachInterrupt(digitalPinToInterrupt(RTC_INT_PIN), setRemotetime, FALLING);
    rtc.clearAlarm(1);  // reset alarm 1, 2 flag on reboot & recompile
    rtc.clearAlarm(2);
    rtc.disableAlarm(2);              // turn off alarm 2 at reboot
    rtc.writeSqwPinMode(DS3231_OFF);  // stop signals at SQW Pin
    rtc.setAlarm1(DateTime(0, 0, 0, 0, 1, 0), DS3231_A1_Hour);
    Serial.println("Alarm(1) set to trigger at midnight");
    Serial.println();
  }

  initWiFi();
  initTime(timezone);  // MST https://leo.leung.xyz/wiki/Timezone
  setRTC();
  getFilenameStatus = true;
  getFilename();
  dateUpdate();
  startLoRA();
  Serial.println("Setup complete. Monitoring ");
  Serial.println();
}

void loop() 
{
  readParseLoRa();
  dateUpdate();
}

Which library is that from ?

ESP32time is a library that theoretically lets you set system time from a GPS, but I have not seen an example to follow

GitHub - fbiego/ESP32Time: An Arduino library for setting and retrieving internal RTC time on ESP32 boards

Nope. This is just calling a variation (function overloading - you can have multiple functions with the same name and different arguments and the compiler picks the right one). Here it’s calling

It’s not recursive - it’s common practice to call deeper functions with less arguments as you aggregate parameters into what’s ultimately required. Good modularity.

It is almost never a good idea to attempt to fix an error by messing with library code. At least you are now stuck forever tracking the source library changes to make sure your 'lifted' code will still work. Lots of people are using GPS as a time source; you just need to find the applicable example.