Logger class

The "Logger" Class handles low power sleep for the main processor, interfacing with the real-time clock and modem, writing to the SD card, and passing data on to the data publishers.

A logger is a device that can control all functions of the modem sensors and that are attached to it and save the values of all variables measured by those sensors to an attached SD card. It must also work with a real-time clock to give timestamps to values. It may also work with a loggerModem for internet connection and send out data over the internet through one or more data publishers.

In this library, all loggers are Arduino-style small processor circuit boards.

Constructors, destructors, conversion operators

Logger(const char* loggerID, const char* samplingFeatureUUID, int16_t loggingIntervalMinutes, int8_t SDCardSSPin, int8_t mcuWakePin, VariableArray* inputArray)
Construct a new Logger object.
Logger(const char* loggerID, int16_t loggingIntervalMinutes, int8_t SDCardSSPin, int8_t mcuWakePin, VariableArray* inputArray)
Construct a new Logger object.
Logger(const char* loggerID, const char* samplingFeatureUUID, int16_t loggingIntervalMinutes, VariableArray* inputArray)
Construct a new Logger object.
Logger(const char* loggerID, const char* samplingFeatureUUID, int16_t loggingIntervalMinutes)
Construct a new Logger object.
Logger(const char* loggerID, int16_t loggingIntervalMinutes, VariableArray* inputArray)
Construct a new Logger object.
Logger()
Construct a new Logger object.
~Logger() virtual
Destroy the Logger object - takes no action.

Basic Logging Parameters

Public functions to get and set basic logging parameters

const char* _loggerID protected
The logger id.
int16_t _loggingIntervalMinutes protected
The logging interval in minutes.
int8_t _remainingShortIntervals protected
The initial number of samples to log at an interval of 1 minute for fast field verification.
int8_t _SDCardSSPin protected
Digital pin number on the mcu controlling the SD card slave select.
int8_t _SDCardPowerPin protected
Digital pin number on the mcu controlling SD card power.
int8_t _mcuWakePin protected
Digital pin number on the mcu receiving interrupts to wake from deep-sleep.
uint8_t _wakePinMode protected
The pin mode used for wake up on the clock alert pin.
int8_t _ledPin protected
Digital pin number on the mcu used to output an alert that the logger is measuring.
int8_t _buttonPin protected
Digital pin number on the mcu receiving interrupts to enter testing mode.
uint8_t _buttonPinMode protected
The pin mode used for interrupts on the testing (button) pin.
const char* _samplingFeatureUUID protected
The sampling feature UUID.
void setLoggerID(const char* loggerID)
Set the Logger ID.
const char* getLoggerID() -> const char*
Get the Logger ID.
void setLoggingInterval(int16_t loggingIntervalMinutes)
Set the logging interval in minutes.
int16_t getLoggingInterval() -> int16_t
Get the Logging Interval.
void setinitialShortIntervals(int16_t initialShortIntervals)
Set the number of initial datapoints to log (and publish) at 1-minute intervals before beginning logging on the regular logging interval.
int16_t getinitialShortIntervals() -> int16_t
Get the number of 1-minute intervals at the start before logging on the regular logging interval.
void setSamplingFeatureUUID(const char* samplingFeatureUUID)
Set the universally unique identifier (UUID or GUID) of the sampling feature.
const char* getSamplingFeatureUUID() -> const char*
Get the Sampling Feature UUID.
void setSDCardPwr(int8_t SDCardPowerPin)
Set a digital pin number (on the mcu) to use to control power to the SD card and activate it as an output pin.
void turnOnSDcard(bool waitToSettle = true)
Send power to the SD card by setting the SDCardPowerPin HIGH.
void turnOffSDcard(bool waitForHousekeeping = true)
Cut power to the SD card by setting the SDCardPowerPin LOW.
void setSDCardSS(int8_t SDCardSSPin)
Set a digital pin number for the slave select (chip select) of the SD card and activate it as an output pin.
void setSDCardPins(int8_t SDCardSSPin, int8_t SDCardPowerPin)
Set both pin numbers related to the SD card and activate them as output pins.
void setRTCWakePin(int8_t mcuWakePin, uint8_t wakePinMode = INPUT_PULLUP)
Set digital pin number for the wake up pin used as an RTC interrupt and activate it in the given pin mode.
void setAlertPin(int8_t ledPin)
Set the digital pin number to put out an alert that a measurement is being logged and activate it as an output pin.
void alertOn()
Set the alert pin high.
void alertOff()
Set the alert pin low.
void setTestingModePin(int8_t buttonPin, uint8_t buttonPinMode = INPUT)
Set the digital pin number for an interrupt pin used to enter testing mode, activate that pin as the given input type, and attach the testing interrupt to it.
void setLoggerPins(int8_t mcuWakePin, int8_t SDCardSSPin, int8_t SDCardPowerPin, int8_t buttonPin, int8_t ledPin, uint8_t wakePinMode = INPUT_PULLUP, uint8_t buttonPinMode = INPUT)
Set the digital pin numbers and activate pin modes for the five pins of interest for the logger.
void enableRTCPinISR() protected
Attaches the RTC ISR to the wake pin.
void enableTestingISR() protected
Attaches the testing ISR to the button pin.

Attached Variable Array Functions

Public functions to get information about the attached variable array

VariableArray* _internalArray protected
A pointer to the internal variable array instance.
void setVariableArray(VariableArray* inputArray)
Set the variable array object.
uint8_t getArrayVarCount() -> uint8_t
Get the number of variables in the internal variable array object.
String getParentSensorNameAtI(uint8_t position_i) -> String
Get the name of the parent sensor of the variable at the given position in the internal variable array object.
String getParentSensorNameAndLocationAtI(uint8_t position_i) -> String
Get the name and pin location of the parent sensor of the variable at the given position in the internal variable array object.
String getVarNameAtI(uint8_t position_i) -> String
Get the name of the variable at the given position in the internal variable array object.
String getVarUnitAtI(uint8_t position_i) -> String
Get the unit of the variable at the given position in the internal variable array object.
String getVarCodeAtI(uint8_t position_i) -> String
Get the customized code of the variable at the given position in the internal variable array object.
const char* getVarUUIDAtI(uint8_t position_i) -> const char*
Get the UUID of the variable at the given position in the internal variable array object.
String getVarUUIDStringAtI(uint8_t position_i) -> String
Get the UUID of the variable at the given position in the internal variable array object.
uint8_t getVarResolutionAtI(uint8_t position_i) -> uint8_t
Get the resolution (number of decimal places) of the variable at the given position in the internal variable array object.
float getValueAtI(uint8_t position_i) -> float
Get the most recent value of the variable at the given position in the internal variable array object.
String getValueStringAtI(uint8_t position_i) -> String
Get the most recent value of the variable at the given position in the internal variable array object.
String formatValueStringAtI(uint8_t position_i, float value) -> String
Get the string representing a particular value of the variable at the given position in the internal variable array object.

Internet and Publisher Functions

Public functions for internet and dataPublishers

loggerModem* _logModem protected
The internal modem instance.
dataPublisher* dataPublishers protected
An array of all of the attached data publishers.
void attachModem(loggerModem& modem)
Attach a loggerModem to the logger to provide internet access.
bool syncRTC() -> bool
Use the attached loggerModem to synchronize the real-time clock with NIST time servers.
loggerModem* registerDataPublisher(dataPublisher* publisher) -> loggerModem*
Register a data publisher object to receive data from the logger.
bool checkRemotesConnectionNeeded(void) -> bool
Check if any data publishers need an Internet connection for the next publish call.
void publishDataToRemotes(bool forceFlush = false)
Publish data to all registered data publishers.
void sendDataToRemotes(void) deprecated in v0.22.5
Retained for backwards compatibility, use publishDataToRemotes() in new code.
void publishMetadataToRemotes()
Publish metadata to all registered data publishers.

SD Cards and Saving Data

Public functions for logging data to an SD card

SdFat sd protected
An internal reference to SdFat for SD card control.
File logFile protected
An internal reference to an SdFat file instance.
String _fileName protected
An internal reference to the current filename.
void setFileName(const char* fileName)
Set the file name, if you want to decide on it in advance.
void setFileName(String& fileName)
Set the file name, if you want to decide on it in advance.
String getFileName(void) -> String
Get the current filename.
void printFileHeader(Stream* stream) virtual
Print a header out to a stream.
void printSensorDataCSV(Stream* stream)
Print a comma separated list of values of sensor data - including the time in the logging timezone - out over an Arduino stream.
bool initializeSDCard(void) -> bool
Check if the SD card is available and ready to write to.
bool createLogFile(String& filename, bool writeDefaultHeader = false) -> bool
Create a file on the SD card and set the created, modified, and accessed timestamps in that file.
bool createLogFile(bool writeDefaultHeader = false) -> bool
Create a file on the SD card and set the created, modified, and accessed timestamps in that file.
bool logToSD(String& filename, String& rec) -> bool
Open a file with the given name on the SD card and append the given line to the bottom of it.
bool logToSD(String& rec) -> bool
Open a file named with the current internal filename value and append the given line to the bottom of it.
bool logToSD(void) -> bool
Open a file named with the current internal filename value and append a line to the bottom of it with the most recent values of all variables in the variable array as a comma separated list.
String generateFileName(bool include_time, const char* extension = nullptr, const char* filePrefix = nullptr) -> String
Generate a file name with the current date and time appended to it.
void generateAutoFileName(void) protected
Generate a file name from the logger id and the current date.
void setFileTimestamp(File& fileToStamp, uint8_t stampFlag) protected
Set a timestamp on a file.
bool openFile(String& filename, bool createFile, bool writeDefaultHeader) -> bool protected
Open or creates a file, converting a string file name to a character file name.
static void fileDateTimeCallback(uint16_t* date, uint16_t* time) protected
This function is used to automatically mark files as created/accessed/modified when operations are done by the SdFat library.

Clock and Timezones

Public functions to access the clock in proper format and time zone

static int8_t _loggerUTCOffset protected
The static timezone data is being logged in.
static epochStart _loggerEpoch protected
The start of the epoch for the logger.
static int8_t _loggerRTCOffset protected
The static difference between the timezone of the RTC and the timezone data is being logged in.
bool setRTClock(time_t UTCEpochSeconds) -> bool deprecated in v0.37.0
Pass-through to loggerClock::setRTClock(time_t UTCEpochSeconds,0, epochStart::unix_epoch) Verify that the input value is sane and if so set the real time clock to the given time.
bool checkInterval(void) -> bool
Check if the CURRENT time is an even interval of the logging rate.
bool checkMarkedInterval(void) -> bool
Check if the MARKED time is an even interval of the logging rate - That is the value saved in the static variable markedLocalUnixTime.
static void setLoggerTimeZone(int8_t timeZone)
Set the static timezone that the data will be logged in.
static int8_t getLoggerTimeZone(void) -> int8_t
Get the Logger Time Zone.
static void setRTCTimeZone(int8_t timeZone) deprecated in v0.37.0
A passthrough to loggerClock::setRTCOffset(int8_t offsetHours); set the static timezone that the RTC is programmed in.
static int8_t getRTCTimeZone(void) -> int8_t deprecated in v0.37.0
A passthrough to loggerClock::getRTCOffset(); get the timezone of the real-time clock (RTC).
static void setTZOffset(int8_t offset)
Set the offset between the built-in clock and the time zone where the data is being recorded.
static int8_t getTZOffset(void) -> int8_t
Get the offset between the built-in clock and the time zone where the data is being recorded.
static time_t getNowLocalEpoch() -> time_t
Get the current epoch time from the RTC and correct it to the logging time zone.
static void getNowParts(int8_t& seconds, int8_t& minutes, int8_t& hours, int8_t& day, int8_t& month, int16_t& year, uint8_t& tz_offset)
Get the current epoch time from the RTC and return it as individual parts.
static time_t getNowUTCEpoch() -> time_t
Get the current Universal Coordinated Time (UTC) epoch time from the RTC.
static String formatDateTime_ISO8601(time_t epochSeconds) -> String
Convert an epoch time into a ISO8601 formatted string.
static void formatDateTime(char* buffer, const char* fmt, time_t epochSeconds)
Convert an epoch time into a character string based on the input strftime format string and put it into the given buffer.
static bool isRTCSane(void) -> bool deprecated in v0.37.0
Passthrough to loggerClock::isRTCSane(); check that the current time on the RTC is within a "sane" range.
static void markTime(void)
Set static variables for the date/time.

Do-It-All Convience Functions

Convience functions to call several of the above functions

static time_t markedLocalUnixTime
The static "marked" epoch time for the local timezone.
static time_t markedUTCUnixTime
The static "marked" epoch time for UTC.
static volatile bool isLoggingNow
Internal flag set to true when logger is currently updating sensors or writing to the SD card.
static volatile bool isTestingNow
Internal flag set to true when the logger is going through the "testing mode" routine.
static volatile bool startTesting
Internal flag set to true when the logger should begin the "testing mode" routine when it finishes other operations.
void begin(const char* loggerID, int16_t loggingIntervalMinutes, VariableArray* inputArray) virtual
Set all pin levels and does initial communication with the real-time clock and SD card to prepare the logger for full functionality.
void begin(VariableArray* inputArray) virtual
Set all pin levels and does initial communication with the real-time clock and SD card to prepare the logger for full functionality.
void begin() virtual
Set all pin levels and does initial communication with the real-time clock and SD card to prepare the logger for full functionality.
void logData(bool sleepBeforeReturning = true) virtual
This is a one-and-done to log data.
void logDataAndPublish(bool sleepBeforeReturning = true) virtual
This is a one-and-done to log data and publish the results to any associated publishers.
void makeInitialConnections() virtual
Wakes and sets up the modem, connects to the internet, syncs the RTC with NIST, and publishes metadata for all attached publishers.

Sleep and Power Saving

Public Functions for sleeping the logger

AVR Sleep modes

In the avr/sleep.h file, the call names of these 5 sleep modes are: SLEEP_MODE_IDLE - the least power savings SLEEP_MODE_ADC SLEEP_MODE_PWR_SAVE SLEEP_MODE_STANDBY SLEEP_MODE_PWR_DOWN - the most power savings

SAMD21 Sleep Modes

The SAM D21/DA1 have two software-selectable sleep modes, Idle and Stand-by. In Idle mode, the CPU is stopped while all other functions can be kept running. In Stand-by mode, all clocks and functions are stopped, expect those selected to continue running. The device supports SleepWalking. This feature allows the peripheral to wake up from sleep based on predefined conditions, and thus allows the CPU to wake up only when needed, e.g., when a threshold is crossed or a result is ready. The Event System supports synchronous and asynchronous events, allowing peripherals to receive, react to and send events even in Stand-by mode.

SAMD51 Sleep Modes

The device can be set in a sleep mode. In sleep mode, the CPU is stopped and the peripherals are either active or idle, according to the sleep mode depth:

  • Idle sleep mode:
    • The CPU is stopped.
    • Synchronous clocks are stopped except when requested.
    • The logic is retained.
  • Standby sleep mode:
    • The CPU is stopped as well as the peripherals.
    • The logic is retained, and power domain gating can be used to fully or partially turn off the PDSYSRAM power domain.
  • Hibernate sleep mode:
    • PDCORESW power domain is turned OFF.
    • The backup power domain is kept powered to allow few features to run (RTC, 32KHz clock sources, and wake-up from external pins).
    • The PDSYSRAM power domain can be retained according to software configuration.
  • Backup sleep mode:
    • Only the backup domain is kept powered to allow few features to run (RTC, 32KHz clock sources, and wake-up from external pins).
    • The PDBKUPRAM power domain can be retained according to software configuration.
  • Off sleep mode:
    • The entire device is powered off.
Bit Settings
ValueNameDefinition
0x0Reserved-
0x1Reserved-
0x2IDLECPU, AHBx, and APBx clocks are OFF
0x3ReservedReserved
0x4STANDBYAll Clocks are OFF
0x5HIBERNATEBackup domain is ON as well as some PDRAMs
0x6BACKUPOnly Backup domain is powered ON
0x7OFFAll power domains are powered OFF
void systemSleep(void)
Put the mcu to sleep to conserve battery life and handle post-interrupt wake actions.
static void wakeISR(void) deprecated in v0.37.0
Set up the Interrupt Service Request for waking.

Sensor Testing Mode

Public functions for a "sensor testing" mode

void benchTestingMode(bool sleepBeforeReturning = true) virtual
Execute bench testing mode if enabled.
static void testingISR(void)
The interrupt service routine called when an interrupt is detected on the pin assigned for "testing" mode.

Function documentation

Logger::Logger(const char* loggerID, const char* samplingFeatureUUID, int16_t loggingIntervalMinutes, int8_t SDCardSSPin, int8_t mcuWakePin, VariableArray* inputArray)

Construct a new Logger object.

Parameters
loggerID A name for the logger - unless otherwise specified, files saved to the SD card will be named with the logger id and the date the file was started.
samplingFeatureUUID The sampling feature UUID.
loggingIntervalMinutes The frequency in minutes at which data should be logged
SDCardSSPin The pin of the chip select/slave select for the SPI connection to the SD card
mcuWakePin The pin used to wake the logger from deep sleep - expected to be attached to an alarm pin of the real-time clock. Use a value of -1 to prevent the board from sleeping.
inputArray A pointer to a variableArray object instance providing data to be logged. This is NOT an array of variables, but an object of the variable array class.

Logger::Logger(const char* loggerID, int16_t loggingIntervalMinutes, int8_t SDCardSSPin, int8_t mcuWakePin, VariableArray* inputArray)

Construct a new Logger object.

Parameters
loggerID A name for the logger - unless otherwise specified, files saved to the SD card will be named with the logger id and the date the file was started.
loggingIntervalMinutes The frequency in minutes at which data should be logged
SDCardSSPin The pin of the chip select/slave select for the SPI connection to the SD card
mcuWakePin The pin used to wake the logger from deep sleep - expected to be attached to an alarm pin of the real-time clock. Use a value of -1 to prevent the board from sleeping.
inputArray A pointer to a variableArray object instance providing data to be logged. This is NOT an array of variables, but an object of the variable array class.

Logger::Logger(const char* loggerID, const char* samplingFeatureUUID, int16_t loggingIntervalMinutes, VariableArray* inputArray)

Construct a new Logger object.

Parameters
loggerID A name for the logger - unless otherwise specified, files saved to the SD card will be named with the logger id and the date the file was started.
samplingFeatureUUID The sampling feature UUID.
loggingIntervalMinutes The frequency in minutes at which data should be logged
inputArray A variableArray object instance providing data to be logged. This is NOT an array of variables, but an object of the variable array class.

Logger::Logger(const char* loggerID, const char* samplingFeatureUUID, int16_t loggingIntervalMinutes)

Construct a new Logger object.

Parameters
loggerID A name for the logger - unless otherwise specified, files saved to the SD card will be named with the logger id and the date the file was started.
samplingFeatureUUID The sampling feature UUID.
loggingIntervalMinutes The frequency in minutes at which data should be logged

Logger::Logger(const char* loggerID, int16_t loggingIntervalMinutes, VariableArray* inputArray)

Construct a new Logger object.

Parameters
loggerID A name for the logger - unless otherwise specified, files saved to the SD card will be named with the logger id and the date the file was started.
loggingIntervalMinutes The frequency in minutes at which data should be logged
inputArray A variableArray object instance providing data to be logged. This is NOT an array of variables, but an object of the variable array class.

Logger::Logger()

Construct a new Logger object.


void Logger::setLoggerID(const char* loggerID)

Set the Logger ID.

Parameters
loggerID A pointer to the logger ID

Unless otherwise specified, files saved to the SD card will be named with the logger id and the date the file was started.


const char* Logger::getLoggerID()

Get the Logger ID.

Returns const char* A pointer to the logger ID

void Logger::setLoggingInterval(int16_t loggingIntervalMinutes)

Set the logging interval in minutes.

Parameters
loggingIntervalMinutes The frequency with which to update sensor values and write data to the SD card.

int16_t Logger::getLoggingInterval()

Get the Logging Interval.

Returns int16_t The logging interval in minutes

void Logger::setinitialShortIntervals(int16_t initialShortIntervals)

Set the number of initial datapoints to log (and publish) at 1-minute intervals before beginning logging on the regular logging interval.

Parameters
initialShortIntervals The number of 1-minute intervals. This number of transmissions will be performed with an interval of 1 minute regardless of the programmed interval. Useful for fast field verification.

int16_t Logger::getinitialShortIntervals()

Get the number of 1-minute intervals at the start before logging on the regular logging interval.

Returns int16_t The number of 1-minute intervals at the start before logging on the regular logging interval

void Logger::setSamplingFeatureUUID(const char* samplingFeatureUUID)

Set the universally unique identifier (UUID or GUID) of the sampling feature.

Parameters
samplingFeatureUUID A pointer to the sampling feature UUID

const char* Logger::getSamplingFeatureUUID()

Get the Sampling Feature UUID.

Returns const char* The sampling feature UUID

void Logger::setSDCardPwr(int8_t SDCardPowerPin)

Set a digital pin number (on the mcu) to use to control power to the SD card and activate it as an output pin.

Parameters
SDCardPowerPin A digital pin number on the mcu controlling power to the SD card.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.


void Logger::turnOnSDcard(bool waitToSettle = true)

Send power to the SD card by setting the SDCardPowerPin HIGH.

Parameters
waitToSettle True to add a short (6ms) delay between powering on the card and beginning initialization. Defaults to true.

Optionally waits for the card to "settle." Has no effect if a pin has not been set to control power to the SD card.


void Logger::turnOffSDcard(bool waitForHousekeeping = true)

Cut power to the SD card by setting the SDCardPowerPin LOW.

Parameters
waitForHousekeeping True to add a 1 second delay between to allow any on-chip writing to complete before cutting power. Defaults to true.

Optionally waits for the card to do "housekeeping" before cutting the power. Has o effect if a pin has not been set to control power to the SD card.


void Logger::setSDCardSS(int8_t SDCardSSPin)

Set a digital pin number for the slave select (chip select) of the SD card and activate it as an output pin.

Parameters
SDCardSSPin The pin on the mcu connected to the slave select of the SD card.

This over-writes the value (if any) given in the constructor. The pin mode of this pin will be set as OUTPUT.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.


void Logger::setSDCardPins(int8_t SDCardSSPin, int8_t SDCardPowerPin)

Set both pin numbers related to the SD card and activate them as output pins.

Parameters
SDCardSSPin The pin on the mcu connected to the slave select of the SD card.
SDCardPowerPin A digital pin number on the mcu controlling power to the SD card.

These over-write the values (if any) given in the constructor. The pin mode of these pins will be set as OUTPUT.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.


void Logger::setRTCWakePin(int8_t mcuWakePin, uint8_t wakePinMode = INPUT_PULLUP)

Set digital pin number for the wake up pin used as an RTC interrupt and activate it in the given pin mode.

Parameters
mcuWakePin The pin on the mcu to be used to wake the mcu from deep sleep.
wakePinMode The pin mode to be used for wake up on the clock alert pin. Must be either INPUT OR INPUT_PULLUP. Optional with a default value of INPUT_PULLUP. The DS3231 has an active low interrupt, so the pull-up resistors should be enabled.

This over-writes the value (if any) given in the constructor. Use a value of -1 to prevent the board from attempting to sleep. If using a SAMD board with the internal RTC, the value of the pin is irrelevant as long as it is positive.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.


void Logger::setAlertPin(int8_t ledPin)

Set the digital pin number to put out an alert that a measurement is being logged and activate it as an output pin.

Parameters
ledPin The pin on the mcu to be held HIGH while sensor data is being collected and logged.

The pin mode of this pin will be set as OUTPUT. This is intended to be a pin with a LED on it so you can see the light come on when a measurement is being taken.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.


void Logger::setTestingModePin(int8_t buttonPin, uint8_t buttonPinMode = INPUT)

Set the digital pin number for an interrupt pin used to enter testing mode, activate that pin as the given input type, and attach the testing interrupt to it.

Parameters
buttonPin The pin on the mcu to listen to for a value-change interrupt.
buttonPinMode The pin mode to be used for the button pin. Must be either INPUT OR INPUT_PULLUP. Optional with a default value of INPUT. Using INPUT_PULLUP will enable processor input resistors, while using INPUT will explicitly disable them. If your pin is externally pulled down or the button is a normally open (NO) switch with common (COM) connected to Vcc, like the EnviroDIY Mayfly), you should use the INPUT pin mode. Conversely, if your button connect to ground when activated, you should enable the processor pull-up resistors using INPUT_PULLUP.

Intended to be used for a pin attached to a button or other manual interrupt source.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.

Once in testing mode, the logger will attempt to connect the the internet and take 25 measurements spaced at 5 second intervals writing the results to the main output destination (ie, Serial). Testing mode cannot be entered while the logger is taking a scheduled measurement. No data is written to the SD card in testing mode.


void Logger::setLoggerPins(int8_t mcuWakePin, int8_t SDCardSSPin, int8_t SDCardPowerPin, int8_t buttonPin, int8_t ledPin, uint8_t wakePinMode = INPUT_PULLUP, uint8_t buttonPinMode = INPUT)

Set the digital pin numbers and activate pin modes for the five pins of interest for the logger.

Parameters
mcuWakePin The pin on the mcu to listen to for a value-change interrupt to wake from deep sleep. The mode of this pin will be set to wakePinMode.
SDCardSSPin The pin on the mcu connected to the slave select of the SD card. The pin mode of this pin will be set as OUTPUT.
SDCardPowerPin A digital pin number on the mcu controlling power to the SD card. The pin mode of this pin will be set as OUTPUT.
buttonPin The pin on the mcu to listen to for a value-change interrupt to enter testing mode. The mode of this pin will be set to buttonPinMode.
ledPin The pin on the mcu to be held HIGH while sensor data is being collected and logged. The pin mode of this pin will be set as OUTPUT.
wakePinMode The pin mode to be used for wake up on the mcuWakePin (clock alert) pin. Must be either INPUT OR INPUT_PULLUP. Optional with a default value of INPUT_PULLUP. The DS3231 has an active low interrupt, so the pull-up resistors should be enabled.
buttonPinMode The pin mode to be used for the button pin. Must be either INPUT OR INPUT_PULLUP. Optional with a default value of INPUT. Using INPUT_PULLUP will enable processor input resistors, while using INPUT will explicitly disable them. If your pin is externally pulled down or the button is a normally open (NO) switch with common (COM) connected to Vcc, like the EnviroDIY Mayfly), you should use the INPUT pin mode. Conversely, if your button is active when connected to ground, you should enable the processor pull-up resistors using INPUT_PULLUP.

Because this sets the pin mode, this function should only be called during the setup() or loop() portion of an Arduino program.


void Logger::enableRTCPinISR() protected

Attaches the RTC ISR to the wake pin.


void Logger::enableTestingISR() protected

Attaches the testing ISR to the button pin.


void Logger::setVariableArray(VariableArray* inputArray)

Set the variable array object.

Parameters
inputArray A pointer to a variable array object instance. This is NOT an array of variables, but an object of the variable array class.

uint8_t Logger::getArrayVarCount()

Get the number of variables in the internal variable array object.

Returns uint8_t The number of variables in the internal variable array object

String Logger::getParentSensorNameAtI(uint8_t position_i)

Get the name of the parent sensor of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The name of the parent sensor of that variable, if applicable.

String Logger::getParentSensorNameAndLocationAtI(uint8_t position_i)

Get the name and pin location of the parent sensor of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The concatenated name and pin location of the parent sensor of that variable, if applicable.

String Logger::getVarNameAtI(uint8_t position_i)

Get the name of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The variable name

Variable names must follow the controlled vocabulary documented here: http://vocabulary.odm2.org/variablename/


String Logger::getVarUnitAtI(uint8_t position_i)

Get the unit of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The variable unit

Variable units must follow the controlled vocabulary documented here: http://vocabulary.odm2.org/units/


String Logger::getVarCodeAtI(uint8_t position_i)

Get the customized code of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The variable code

const char* Logger::getVarUUIDAtI(uint8_t position_i)

Get the UUID of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns const char* The variable UUID

String Logger::getVarUUIDStringAtI(uint8_t position_i)

Get the UUID of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The variable UUID

uint8_t Logger::getVarResolutionAtI(uint8_t position_i)

Get the resolution (number of decimal places) of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns uint8_t The variable resolution

float Logger::getValueAtI(uint8_t position_i)

Get the most recent value of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns float The value of the variable as a float.

String Logger::getValueStringAtI(uint8_t position_i)

Get the most recent value of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
Returns String The value of the variable as a string with the correct number of significant figures.

String Logger::formatValueStringAtI(uint8_t position_i, float value)

Get the string representing a particular value of the variable at the given position in the internal variable array object.

Parameters
position_i The position of the variable in the array.
value The value to format.
Returns String The given value as a string with the correct number of significant figures.

void Logger::attachModem(loggerModem& modem)

Attach a loggerModem to the logger to provide internet access.

Parameters
modem An instance of the loggerModem class

See Modem and Internet Functions for more information on how the modem must be set up before it is attached to the logger. You must include an ampersand to tie in the already created modem! If you do not attach a modem, no action will be taken to publish data.


bool Logger::syncRTC()

Use the attached loggerModem to synchronize the real-time clock with NIST time servers.

Returns bool True if clock synchronization was successful

loggerModem* Logger::registerDataPublisher(dataPublisher* publisher)

Register a data publisher object to receive data from the logger.

Parameters
publisher A dataPublisher object
Returns loggerModem* A pointer to the underlying logger's loggerModem to use for chaining

bool Logger::checkRemotesConnectionNeeded(void)

Check if any data publishers need an Internet connection for the next publish call.

Returns bool True if any remotes need a connection.

void Logger::publishDataToRemotes(bool forceFlush = false)

Publish data to all registered data publishers.

Parameters
forceFlush Ask the publishers to flush buffered data immediately.

void Logger::sendDataToRemotes(void) deprecated in v0.22.5

Retained for backwards compatibility, use publishDataToRemotes() in new code.


void Logger::publishMetadataToRemotes()

Publish metadata to all registered data publishers.

This should only be called at startup.


void Logger::setFileName(const char* fileName)

Set the file name, if you want to decide on it in advance.

Parameters
fileName The file name

If the file name is set using this function, the same file name will be used for every single file created by the logger.


void Logger::setFileName(String& fileName)

Set the file name, if you want to decide on it in advance.

Parameters
fileName The file name

If the file name is set using this function, the same file name will be used for every single file created by the logger.


String Logger::getFileName(void)

Get the current filename.

Returns String The name of the file data is currently being saved to.

This may be a single filename set using the setFileName(name) function or an auto-generated filename which is a concatenation of the logger id and the date when the file was started.


void Logger::printFileHeader(Stream* stream) virtual

Print a header out to a stream.

Parameters
stream An Arduino stream instance - expected to be an SdFat file - but could also be the "main" Serial port for debugging.

This removes need to pass around very long string objects which can crash the logger


void Logger::printSensorDataCSV(Stream* stream)

Print a comma separated list of values of sensor data - including the time in the logging timezone - out over an Arduino stream.

Parameters
stream An Arduino stream instance - expected to be an SdFat file - but could also be the "main" Serial port for debugging.

bool Logger::initializeSDCard(void)

Check if the SD card is available and ready to write to.

Returns bool True if the SD card is ready

We run this check before every communication with the SD card to prevent hanging.


bool Logger::createLogFile(String& filename, bool writeDefaultHeader = false)

Create a file on the SD card and set the created, modified, and accessed timestamps in that file.

Parameters
filename The name of the file to create
writeDefaultHeader True to write a header to the file, default is false
Returns bool True if the file was successfully created.

The filename will be the value specified in the function. If desired, a header will also be written to the file based on the variable information from the variable array. This can be used to force a logger to create a file with a secondary file name.


bool Logger::createLogFile(bool writeDefaultHeader = false)

Create a file on the SD card and set the created, modified, and accessed timestamps in that file.

Parameters
writeDefaultHeader True to write a header to the file, default is false
Returns bool True if the file was successfully created.

The filename will be the one set by setFileName(String) or generated using the logger id and the date. If desired, a header will also be written to the file based on the variable information from the variable array.


bool Logger::logToSD(String& filename, String& rec)

Open a file with the given name on the SD card and append the given line to the bottom of it.

Parameters
filename The name of the file to write to
rec The line to be written to the file
Returns bool True if the file was successfully accessed or created and data appended to it.

If a file with the specified name does not already exist, attempt to create the file and add a header to it. Set the modified and accessed timestamps of the file to the current time.


bool Logger::logToSD(String& rec)

Open a file named with the current internal filename value and append the given line to the bottom of it.

Parameters
rec The line to be written to the file
Returns bool True if the file was successfully accessed or created and data appended to it.

If a file with the with the internal filename does not already exist, attempt to create a file with that name and add a header to it. Set the modified and accessed timestamps of the file to the current time.


bool Logger::logToSD(void)

Open a file named with the current internal filename value and append a line to the bottom of it with the most recent values of all variables in the variable array as a comma separated list.

Returns bool True if the file was successfully accessed or created and data appended to it.

If a file with the with the internal filename does not already exist, attempt to create the file and add a header to it. Set the modified and accessed timestamps of the file to the current time.


String Logger::generateFileName(bool include_time, const char* extension = nullptr, const char* filePrefix = nullptr)

Generate a file name with the current date and time appended to it.

Parameters
include_time True to include the time in the filename
extension The file extension to use
filePrefix The prefix to use for the file name, optional, with an default value of nullptr. If not provided, the logger ID will be used.
Returns String The generated file name

void Logger::generateAutoFileName(void) protected

Generate a file name from the logger id and the current date.


void Logger::setFileTimestamp(File& fileToStamp, uint8_t stampFlag) protected

Set a timestamp on a file.

Parameters
fileToStamp The filename to change the timestamp of
stampFlag The "flag" of the timestamp to change - should be T_CREATE, T_WRITE, or T_ACCESS

bool Logger::openFile(String& filename, bool createFile, bool writeDefaultHeader) protected

Open or creates a file, converting a string file name to a character file name.

Parameters
filename The name of the file to open
createFile True to create the file if it did not already exist
writeDefaultHeader True to add a header to the file if it is created
Returns bool True if a file was successfully opened or created.

static void Logger::fileDateTimeCallback(uint16_t* date, uint16_t* time) protected

This function is used to automatically mark files as created/accessed/modified when operations are done by the SdFat library.

Parameters
date Pointer to a uint16_t to store the date
time Pointer to a uint16_t to store the time

This function will be called automatically by SdFat, but is not intended to be used at any other time.


bool Logger::setRTClock(time_t UTCEpochSeconds) deprecated in v0.37.0

Pass-through to loggerClock::setRTClock(time_t UTCEpochSeconds,0, epochStart::unix_epoch) Verify that the input value is sane and if so set the real time clock to the given time.

Parameters
UTCEpochSeconds The number of seconds since 1970 in UTC.
Returns bool True if the input timestamp passes sanity checks and the clock has been successfully set.

Call loggerClock::setRTClock(time_t ts, int8_t utcOffset , epochStart epoch) directly in new programs.


bool Logger::checkInterval(void)

Check if the CURRENT time is an even interval of the logging rate.

Returns bool True if the current time on the RTC is an even interval of the logging rate.

bool Logger::checkMarkedInterval(void)

Check if the MARKED time is an even interval of the logging rate - That is the value saved in the static variable markedLocalUnixTime.

Returns bool True if the marked time is an even interval of the logging rate.

This should be used in conjunction with markTime() to ensure that all data outputs from a single data update session (SD, EnviroDIY, serial printing, etc) have the same timestamp even though the update routine may take several (or many) seconds.


static void Logger::setLoggerTimeZone(int8_t timeZone)

Set the static timezone that the data will be logged in.

Parameters
timeZone The timezone data should be saved to the SD card in. This need not be the same as the timezone of the real time clock.

static int8_t Logger::getLoggerTimeZone(void)

Get the Logger Time Zone.

Returns int8_t The timezone data is be saved to the SD card in. This is not be the same as the timezone of the real time clock.

static void Logger::setRTCTimeZone(int8_t timeZone) deprecated in v0.37.0

A passthrough to loggerClock::setRTCOffset(int8_t offsetHours); set the static timezone that the RTC is programmed in.

Parameters
timeZone The offset of the real-time clock (RTC) from UTC in hours

Use loggerClock::setRTCOffset(_offsetHours) in new code!


static int8_t Logger::getRTCTimeZone(void) deprecated in v0.37.0

A passthrough to loggerClock::getRTCOffset(); get the timezone of the real-time clock (RTC).

Returns int8_t The offset of the real-time clock (RTC) from UTC in hours

Use loggerClock::getRTCOffset() in new code!


static void Logger::setTZOffset(int8_t offset)

Set the offset between the built-in clock and the time zone where the data is being recorded.

Parameters
offset The difference between the timezone of the RTC and the saved data

If your RTC is set in UTC and your logging timezone is EST, this should be -5. If your RTC is set in EST and your timezone is EST this does not need to be called.


static int8_t Logger::getTZOffset(void)

Get the offset between the built-in clock and the time zone where the data is being recorded.

Returns int8_t The offset between the built-in clock and the time zone where the data is being recorded.

static time_t Logger::getNowLocalEpoch()

Get the current epoch time from the RTC and correct it to the logging time zone.

Returns time_t The number of seconds from the start of the UNIX epoch in the logging time zone.

static void Logger::getNowParts(int8_t& seconds, int8_t& minutes, int8_t& hours, int8_t& day, int8_t& month, int16_t& year, uint8_t& tz_offset)

Get the current epoch time from the RTC and return it as individual parts.

Parameters
seconds [out] Reference to a variable where the seconds will be stored
minutes [out] Reference to a variable where the minutes will be stored
hours [out] Reference to a variable where the hours will be stored
day [out] Reference to a variable where the day will be stored
month [out] Reference to a variable where the month will be stored
year [out] Reference to a variable where the year will be stored
tz_offset [out] Reference to a variable where the timezone offset will be stored

static time_t Logger::getNowUTCEpoch()

Get the current Universal Coordinated Time (UTC) epoch time from the RTC.

Returns time_t The number of seconds from the start of the UNIX epoch.

static String Logger::formatDateTime_ISO8601(time_t epochSeconds)

Convert an epoch time into a ISO8601 formatted string.

Parameters
epochSeconds The number of seconds since the start of the logger's epoch (MS_LOGGER_EPOCH).
Returns String An ISO8601 formatted String.

This assumes the supplied date/time is in the LOGGER's timezone and the LOGGER's epoch start. It adds the LOGGER's offset as the time zone offset in the string.


static void Logger::formatDateTime(char* buffer, const char* fmt, time_t epochSeconds)

Convert an epoch time into a character string based on the input strftime format string and put it into the given buffer.

Parameters
buffer A buffer to put the finished string into. Make sure that the buffer is big enough to hold all of the characters!
fmt The strftime format string.
epochSeconds The number of seconds since the start of the given epoch in the given offset from UTC.

This assumes the supplied date/time is in the LOGGER's timezone and adds the LOGGER's offset as the time zone offset in the string.


static bool Logger::isRTCSane(void) deprecated in v0.37.0

Passthrough to loggerClock::isRTCSane(); check that the current time on the RTC is within a "sane" range.

Returns bool True if the current time on the RTC passes sanity range checking

Use loggerClock::isRTCSane() directly in new code!

To be sane the clock must be between EARLIEST_SANE_UNIX_TIMESTAMP and LATEST_SANE_UNIX_TIMESTAMP.


static void Logger::markTime(void)

Set static variables for the date/time.

This is needed so that all data outputs (SD, EnviroDIY, serial printing, etc) print the same time for updating the sensors - even though the routines to update the sensors and to output the data may take several seconds. It is not currently possible to output the instantaneous time an individual sensor was updated, just a single marked time. By custom, this should be called before updating the sensors, not after.


void Logger::begin(const char* loggerID, int16_t loggingIntervalMinutes, VariableArray* inputArray) virtual

Set all pin levels and does initial communication with the real-time clock and SD card to prepare the logger for full functionality.

Parameters
loggerID An ID for the logger - will be used to auto-generate file names. Supplying a logger ID here will override any value given in the constructor.
loggingIntervalMinutes The interval in minutes at which to log data. Supplying an interval here will override any value given in the constructor.
inputArray A variableArray object instance providing data to be logged. This is NOT an array of variables, but an object of the variable array class. Supplying a variableArray object here will override any value given in the constructor.

This is used for operations that cannot happen in the logger constructor

  • they must happen at run time, not at compile time.

void Logger::begin(VariableArray* inputArray) virtual

Set all pin levels and does initial communication with the real-time clock and SD card to prepare the logger for full functionality.

Parameters
inputArray A variableArray object instance providing data to be logged. This is NOT an array of variables, but an object of the variable array class. Supplying a variableArray object here will override any value given in the constructor.

This is used for operations that cannot happen in the logger constructor

  • they must happen at run time, not at compile time.

void Logger::begin() virtual

Set all pin levels and does initial communication with the real-time clock and SD card to prepare the logger for full functionality.

This is used for operations that cannot happen in the logger constructor

  • they must happen at run time, not at compile time.

void Logger::logData(bool sleepBeforeReturning = true) virtual

This is a one-and-done to log data.

Parameters
sleepBeforeReturning True to put the logger to sleep before returning from the function; optional with a default value of true.

void Logger::logDataAndPublish(bool sleepBeforeReturning = true) virtual

This is a one-and-done to log data and publish the results to any associated publishers.

Parameters
sleepBeforeReturning True to put the logger to sleep before returning from the function; optional with a default value of true.

void Logger::makeInitialConnections() virtual

Wakes and sets up the modem, connects to the internet, syncs the RTC with NIST, and publishes metadata for all attached publishers.

This is only to be run at startup. It should be run after beginning the logger and attaching the modem and sensors.


void Logger::systemSleep(void)

Put the mcu to sleep to conserve battery life and handle post-interrupt wake actions.


static void Logger::wakeISR(void) deprecated in v0.37.0

Set up the Interrupt Service Request for waking.

In this case, we're doing nothing, we just want the processor to wake. This must be a static function (which means it can only call other static functions.)

Use loggerClock::rtcISR() in new code!


void Logger::benchTestingMode(bool sleepBeforeReturning = true) virtual

Execute bench testing mode if enabled.

Parameters
sleepBeforeReturning True to put the logger to sleep before returning from the function; optional with a default value of true.

In testing mode, the logger uses the loggerModem, if attached, to connect to the internet. It then powers up all sensors tied to variable in the internal variable array. The logger then updates readings from all sensors 25 times with a 5 second wait in between. All results are output to the "main" output - ie Serial - and NOT to the SD card. After 25 measurements, the sensors are put to sleep, the modem is disconnected from the internet, and the logger goes back to sleep.



Variable documentation

uint8_t Logger::_wakePinMode protected

The pin mode used for wake up on the clock alert pin.

Must be either INPUT OR INPUT_PULLUP with an AVR board. On a SAM/D board INPUT_PULLDOWN is also an option. Optional with a default value of INPUT_PULLUP. The DS3231 has an active low interrupt, so the pull-up resistors should be enabled.


int8_t Logger::_ledPin protected

Digital pin number on the mcu used to output an alert that the logger is measuring.

Expected to be connected to a LED.


int8_t Logger::_buttonPin protected

Digital pin number on the mcu receiving interrupts to enter testing mode.

Expected to be connected to a user button.


uint8_t Logger::_buttonPinMode protected

The pin mode used for interrupts on the testing (button) pin.

Must be either INPUT OR INPUT_PULLUP with an AVR board. On a SAM/D board INPUT_PULLDOWN is also an option. Optional with a default value of INPUT_PULLUP.


loggerModem* Logger::_logModem protected

The internal modem instance.


static int8_t Logger::_loggerUTCOffset protected

The static timezone data is being logged in.


static epochStart Logger::_loggerEpoch protected

The start of the epoch for the logger.


static int8_t Logger::_loggerRTCOffset protected

The static difference between the timezone of the RTC and the timezone data is being logged in.