fabianoriccardi / ESPLogger

An Arduino library providing a minimal interface to log data on flash memory and SD cards with ESP8266 and ESP32.
GNU Lesser General Public License v2.1
82 stars 15 forks source link

Library incompatible with newest version of Ticker library #9

Open dduehren opened 3 years ago

dduehren commented 3 years ago

`n file included from D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp:29:0:

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.h: In constructor 'LoggerRoutine::LoggerRoutine(Logger&, float)':

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.h:44:20: error: no matching function for call to 'Ticker::Ticker()'

   period(period){}; 

                ^

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.h:44:20: note: candidates are:

In file included from D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.h:32:0,

             from D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp:29:

D:\David\MyDocuments\Arduino\libraries\Ticker/Ticker.h:74:2: note: Ticker::Ticker(fptr, uint32_t, uint32_t, resolution_t)

Ticker(fptr callback, uint32_t timer, uint32_t repeat = 0, resolution_t resolution = MICROS);

^

D:\David\MyDocuments\Arduino\libraries\Ticker/Ticker.h:74:2: note: candidate expects 4 arguments, 0 provided

D:\David\MyDocuments\Arduino\libraries\Ticker/Ticker.h:62:7: note: Ticker::Ticker(const Ticker&)

class Ticker {

   ^

D:\David\MyDocuments\Arduino\libraries\Ticker/Ticker.h:62:7: note: candidate expects 1 argument, 0 provided

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp: In function 'void routine(LoggerRoutine*)':

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp:33:17: error: 'class Ticker' has no member named 'attach'

logRun->ticker.attach(logRun->period,routine,logRun);

             ^

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp: In member function 'bool LoggerRoutine::begin(bool)':

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp:41:10: error: 'class Ticker' has no member named 'attach'

ticker.attach(period, routine, this);

      ^

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp: In member function 'void LoggerRoutine::setPeriod(float, bool)':

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp:53:10: error: 'class Ticker' has no member named 'detach'

ticker.detach();

      ^

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src\logger_routine.cpp:54:10: error: 'class Ticker' has no member named 'attach'

ticker.attach(period, routine, this);

      ^`
fabianoriccardi commented 3 years ago

Hi David, I need to know which version of board you are using (esp8266 or esp32) and the version of the core. I had just tested the latest version of esp8266 and esp32 and both works.

dduehren commented 3 years ago

I’m using the 8266 with the Arduino Ide. If you can send me your working one, that would be helpful. For me it kept saying Logger wasn’t a type or something like that.

Sent from my iPhone

David Duehren

On Mar 14, 2021, at 7:31 AM, Fabiano Riccardi @.***> wrote:

 Hi David, I need to know which version of board you are using (esp8266 or esp32) and the version of the core. I had just tested the latest version of esp8266 and esp32 and both works.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

fabianoriccardi commented 3 years ago

okI had used version arduino8266 version 2.7.4 to test the library. All the examples seem to compiled and work properly. Can you send me the code that do not compile?

dduehren commented 3 years ago

Hi Faviano,

Here’s my Class definition where I try to instantiate it. It follow the model I used for the BME library in another class. The message I get when I try to compile is 'LoggerSPIFFS' does not name a type. This exact same line, when put in the main ino, works fine, and I’ve made progress by declaring at external in my cpp file.

Thanks for your attention on this,

David Duehren

The includes are:

ifndef MUSH_LOGGER_H

define MUSH_LOGGER_H

include

include

include

include

class Mush_Logger {

public:

Mush_Logger();

void init();

void setLogLevel(int const log_level);

void log(int const log_level, const char  *fmt, ...);

void handle();

String getLogFile(int fileID) const;

String getLogLevel()const;

private:   

LoggerSPIFFS mushLog("/log/Mushlog.log"); 

int log_type;

int _log_level;

int logcsvlevel;

void initArrays();

bool saveLogArray();

bool loadLogArray();

void lPrint(char const * fmt, va_list args);

void logCSVheader();

void logCSVdata();

bool shouldLog(int const log_level) const;

File loggerFile;

File configFile;

struct csvCell{

  char colName[COL_WIDTH];

  char colVal[VAL_WIDTH];

};

csvCell csvArray[NoCol];

String logFiles[FileNo]; // array for circulating log file names

int logFilePtr;

int dayCtr;

};

From: Fabiano Riccardi @.> Sent: Sunday, March 14, 2021 9:58 AM To: fabiuz7/esp-logger-lib @.> Cc: David Duehren @.>; Author @.> Subject: Re: [fabiuz7/esp-logger-lib] Library incompatible with newest version of Ticker library (#9)

I had used version @.*** to test the library. All the examples seem to compiled and work properly. Can you send me the code that do not compile?

Fabiano Riccardi

Da: David @.> Inviato: domenica 14 marzo 2021 17.53 A: @.> Cc: Fabiano @.>; @.> Oggetto: Re: [fabiuz7/esp-logger-lib] Library incompatible with newest version of Ticker library (#9)

I’m using the 8266 with the Arduino Ide. If you can send me your working one, that would be helpful. For me it kept saying Logger wasn’t a type or something like that.

Sent from my iPhone

David Duehren

On Mar 14, 2021, at 7:31 AM, Fabiano Riccardi @.***> wrote:

 Hi David, I need to know which version of board you are using (esp8266 or esp32) and the version of the core. I had just tested the latest version of esp8266 and esp32 and both works.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/fabiuz7/esp-logger-lib/issues/9#issuecomment-798940235, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AB4R44A2G7RWKK4Q45UYCHDTDTSW3ANCNFSM4YYAHQTQ.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/fabiuz7/esp-logger-lib/issues/9#issuecomment-798940916 , or unsubscribe https://github.com/notifications/unsubscribe-auth/ACAY6ZZSIRDVZXNBR7OLM3LTDTTI5ANCNFSM4YYAHQTQ .

dduehren commented 3 years ago

I’m using version 1.3, the latest installed via the Arduino library manager. Seems the IDE install is far behind. Are these the same version numbers?

Sent from my iPhone

David Duehren

On Mar 14, 2021, at 9:58 AM, Fabiano Riccardi @.***> wrote:

 okI had used version arduino8266 version 2.7.4 to test the library. All the examples seem to compiled and work properly. Can you send me the code that do not compile?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

dduehren commented 3 years ago

I was talking about your library. I am using version 2.7.4 of 8266 Arduino library

Sent from my iPhone

David Duehren

On Mar 14, 2021, at 9:58 AM, Fabiano Riccardi @.***> wrote:

 okI had used version arduino8266 version 2.7.4 to test the library. All the examples seem to compiled and work properly. Can you send me the code that do not compile?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

dduehren commented 3 years ago

As you'll see from my code, I'm trying to build a front end that is easy to use, convert to CSV in the middle, and rather than do regular flushes, use a rotating file system. I haven't fully tested it yet, but it's mostly working with the extern declaration. I'm also attaching the .ino.

include "mushLogger.h"

include "Arduino_DebugUtils.h"

include

include

extern LoggerSPIFFS mushLog; //I didn't find a way to make LoggerSPIFFS work inside a class extern NTPClient timeClient; /**** CONSTANTS **/

static int const DEFAULT_LOG_LEVEL = LOG_OPS; const char COL_TMP[COL_WIDTH] PROGMEM = "TMP"; const char COL_HUM[COL_WIDTH] PROGMEM = "HUM"; const char COL_CO2[COL_WIDTH] PROGMEM = "CO2"; const char COL_A0I[COL_WIDTH] PROGMEM = "A0I"; const char COL_FSd[COL_WIDTH] PROGMEM = "FSd"; const char COL_OPN[COL_WIDTH] PROGMEM = "OPN"; const char COL_FAN[COL_WIDTH] PROGMEM = "FAN"; const char COL_LED[COL_WIDTH] PROGMEM = "LED"; const char COL_RL1[COL_WIDTH] PROGMEM = "RL1"; const char COL_RL2[COL_WIDTH] PROGMEM = "RL2"; const char COL_RL3[COL_WIDTH] PROGMEM = "RL3"; const char COL_RL4[COL_WIDTH] PROGMEM = "RL4"; const char COL_OP1[COL_WIDTH] PROGMEM = "OP1"; const char COL_OP2[COL_WIDTH] PROGMEM = "OP2"; const char COL_OP3[COL_WIDTH] PROGMEM = "OP3"; const char COL_OP4[COL_WIDTH] PROGMEM = "OP4"; const char COL_IF1[COL_WIDTH] PROGMEM = "IF1"; const char COL_IF2[COL_WIDTH] PROGMEM = "IF2"; const char COL_IF3[COL_WIDTH] PROGMEM = "IF3"; const char COL_IF4[COL_WIDTH] PROGMEM = "IF4";

/*****

/* CTOR/DTOR **/ Mush_Logger::Mush_Logger(){ setLogLevel(DEFAULT_LOG_LEVEL); // initArrays(); } /**** PUBLIC MEMBER FUNCTIONS *****/

void Mush_Logger::log(int const log_level, const char *fmt, ...){ Debug.print(DBG_INFO, "log method: log_level: %d", log_level); //extract the data, eventually creating a string for mushlog.append(record.c_str() if (!shouldLog(log_level)) return; String fmt_str(fmt); va_list args; va_start(args, fmt_str.c_str()); lPrint(fmt_str.c_str(), args); va_end(args); // sync inputs to the 1 second sensor logging if(log_level==LOG_INPUTS){ logCSVdata(); } }

void Mush_Logger::handle(){ // manage revolving log files. This handler should be started every 6 hours by external timer // remove current filename if(logFilePtr >= FileNo){ Debug.print(DBG_ERROR, "logFilePtr>=16!!!!!! %d", FileNo); logFilePtr = 0; } String logFileName; logFileName = logFiles[logFilePtr]; if (logFileName != "EMPTY"){ if (SPIFFS.exists(logFileName)){ if(SPIFFS.remove(logFileName)){ Debug.print(DBG_INFO, "File removed %s", logFileName.c_str()); } else { Debug.print(DBG_ERROR, "log file removal failed %s", logFileName.c_str()); } } } //create new file name logFileName = "/log/"+String(dayCtr)+String(timeClient.getHours())+String(timeClient.getMinutes())+".log"; Debug.print(DBG_INFO, "New file name %s, logFilePtr: %d", logFileName.c_str(), logFilePtr); if (SPIFFS.rename("/log/Mushlog.log",logFileName)){ logFiles[logFilePtr] = logFileName; //save new filename //presume Mushlog.log doesn't exist because it's been renamed. if (SPIFFS.exists("/log/Mushlog.log")){ Debug.print(DBG_WARNING, "Mushlog exists after renaming"); } loggerFile=SPIFFS.open("/log/Mushlog.log","a"); logCSVheader(); //add header row } else { Debug.print(DBG_ERROR, "Rename of Mushlog failed"); } // garbage collection SPIFFS.gc(); // update pointers logFilePtr++; Debug.print(DBG_INFO,"Just after logFilePtr++, logFilePtr: %d", logFilePtr); if(logFilePtr >= FileNo){ // This check is not being executed for some reason. Debug.print(DBG_INFO, "Compare to FileNo succeeded"); logFilePtr==0; } Debug.print(DBG_INFO, "Just after compare, logFilePtr: %d", logFilePtr); if ((logFilePtr % 4) == 0){ dayCtr++; } if (dayCtr > DayMax){ dayCtr=0; } // Save logArray // Because it's being saved here at 16. if(!saveLogArray()){ Debug.print(DBG_ERROR, "Saving LogArray Failed"); } }

void Mush_Logger::init(){ mushLog.begin(); mushLog.setFlusherCallback(flush); mushLog.reset(); // for now until the file management system is working mushLog.setSizeLimit(65535); //default is 1000 Serial.print("Log file size: "); Serial.println(mushLog.getSizeLimit()); mushLog.setSizeLimitPerChunk(200); // default is 100 mushLog.setOneRecordPerChunk(true); if(mushLog.getActualSize()<10){ logCSVheader(); //add header row } Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); initArrays(); / char temch[8]; for (int i=0; i<NoCol; i++){ strcpy(temch, csvArray[i].colName); Serial.print(temch); Serial.print(" : "); strcpy (temch, csvArray[i].colVal); Serial.println(temch); } / }

void Mush_Logger::setLogLevel(int const log_level){ _log_level = log_level; logcsvlevel =0; switch(_log_level){ case LOG_INPUTS: logcsvlevel=LogInputLevel; break; case LOG_CONTROLS: logcsvlevel=LogControlLevel; break; case LOG_OPS: logcsvlevel=LogOpsLevel; break; case LOG_ALL: logcsvlevel=NoCol; break; default: logcsvlevel=NoCol; break; } } String Mush_Logger::getLogFile(int fileID) const { return(logFiles[fileID]); } String Mush_Logger::getLogLevel() const { switch(_log_level){ case LOG_NONE: return("LOG_NONE"); break; case LOG_INPUTS: return("LOG_INPUTS"); break; case LOG_CONTROLS: return("LOG_CONTROLS"); break; case LOG_OPS: return("LOG_OPS"); break; case LOG_ALL: return("LOG_ALL"); break; default: return("LOG_ALL"); break; } }

/***** Private member functions **/ void Mush_Logger::initArrays(){ // Init csvArray //first set all values to "NAN"; for (int i = 0; i < NoCol; i++) { strcpy(csvArray[i].colVal, "NAN"); } strcpy(csvArray[0].colName, "TIM"); strcpy(csvArray[1].colName, COL_TMP); strcpy(csvArray[2].colName, COL_HUM); strcpy(csvArray[3].colName, COL_CO2); strcpy(csvArray[4].colName, COL_A0I); strcpy(csvArray[5].colName, COL_FSd); strcpy(csvArray[6].colName, COL_OPN); strcpy(csvArray[7].colName, COL_FAN); strcpy(csvArray[8].colName, COL_LED); strcpy(csvArray[9].colName, COL_RL1); strcpy(csvArray[10].colName, COL_RL2); strcpy(csvArray[11].colName, COL_RL3); strcpy(csvArray[12].colName, COL_RL4); strcpy(csvArray[13].colName, COL_OP1); strcpy(csvArray[14].colName, COL_OP2); strcpy(csvArray[15].colName, COL_OP3); strcpy(csvArray[16].colName, COL_OP4); strcpy(csvArray[17].colName, COL_IF1); strcpy(csvArray[18].colName, COL_IF2); strcpy(csvArray[19].colName, COL_IF3); strcpy(csvArray[20].colName, COL_IF4); /**

void Mush_Logger::lPrint(char const * fmt, va_list args){ static size_t const MSG_BUF_SIZE = 120; char msg_buf[MSG_BUF_SIZE] = {0};

vsprintf(msg_buf, fmt, args); Debug.print(DBG_INFO, "msg_buf: %s", msg_buf); // process the string into columns and values char tempCol[COL_WIDTH]; char key1=':'; char key2=','; char pcol; char pcom; char * ecol; char colTemp[COL_WIDTH]; colTemp[3]='\0'; pcom = msg_buf; ecol = strrchr(msg_buf, key1); pcol = strchr(msg_buf, key1); while (pcol!=NULL) { strncpy(colTemp, pcom, COL_WIDTH-1); if (pcol==ecol){ pcom = strchr(pcom+1, '\0'); //end of string } else { pcom = strchr(pcom+1, key2); //find comma, other way to end variable } for (int i=0; i<NoCol; i++){ if(strcmp(colTemp, csvArray[i].colName)==0){ Debug.print(DBG_VERBOSE,"Match %s", colTemp); pcol++; //point to variable strncpy(colTemp, pcol,(pcom-pcol)); if ((pcom-pcol)<3){ for(int i=(pcom-pcol); i<3; i++){ colTemp[i]='\0'; } colTemp[3]='\0'; strcpy(csvArray[i].colVal, colTemp);
} else { strncpy(csvArray[i].colVal, pcol,(pcom-pcol)); } strcpy(colTemp, csvArray[i].colVal); colTemp[3]='\0'; //reset colTemp after use for printingcol i=NoCol; // end search } else { } } // end of 4 loop pcol = strchr(pcol+1, key1); pcom++; //point to next column name } String record=""; record=""; for(int i=15; i<NoCol; i++){ record = record+csvArray[i].colVal+','; } Serial.printf("tail csvArray %s", record.c_str()); Serial.println("<>"); } void Mush_Logger::logCSVheader(){ String record=""; for(int i=0; i<logcsvlevel; i++){ if (i<logcsvlevel-1){ record = record+csvArray[i].colName+','; } else { record = record+csvArray[i].colName; } } Debug.print(DBG_INFO,"%s", record.c_str()); mushLog.append(record,0); //append adds CRLF Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); }

void Mush_Logger::logCSVdata(){ Debug.print(DBG_INFO,"logcsvlevel: %d", logcsvlevel); String record=""; record= record+timeClient.getFormattedTime()+','; for(int i=1; i<logcsvlevel; i++){ if (i<logcsvlevel-1){ record = record+csvArray[i].colVal+','; } else { record = record+csvArray[i].colVal; } } Debug.print(DBG_INFO,"%s", record.c_str()); mushLog.append(record,0); // clear array for next round for (int i = 0; i < NoCol; i++) { strcpy(csvArray[i].colVal, "NAN"); } Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); }

bool Mush_Logger::shouldLog(int const log_level) const { return((log_level > LOG_NONE) && (log_level <= LOG_ALL) && (log_level <= _log_level)); }

bool Mush_Logger::saveLogArray(){ configFile = SPIFFS.open("/logArray.txt", "w"); if (!configFile) { Debug.print(DBG_ERROR,"Failed to open logArray file for writing"); return false; } configFile.seek(0); //rewind file so test data is not appended for(int i=0; i<FileNo; i++){ configFile.print(logFiles[i]); if(i<FileNo){ configFile.print(","); } } char record[10]; snprintf(record, 10, "%d,%d,\n", logFilePtr, dayCtr); configFile.print(record); configFile.close(); Serial.println("****"); Debug.print(DBG_DEBUG, "saveLogArray"); for (int i; i<FileNo; i++){ Serial.print(logFiles[i]); Serial.print("|"); if(i%4==0){ Serial.print("\n"); } } Serial.println("<"); Serial.printf("logFilePtr: %d, dayCtr: %d", logFilePtr, dayCtr); Serial.println(">"); return true; } bool Mush_Logger::loadLogArray(){ if (SPIFFS.exists("/logArray.txt")){ File configFile = SPIFFS.open("/logArray.txt", "r"); if (!configFile) { Debug.print(DBG_ERROR, "Failed to open logArray file"); return false; } for (int i=0; i<FileNo; i++){ logFiles[i]=configFile.readStringUntil(','); } String srec = configFile.readStringUntil(','); logFilePtr=srec.toInt(); srec = configFile.readStringUntil(','); dayCtr=srec.toInt();
Serial.println("****"); Debug.print(DBG_DEBUG, "loadLogArray"); for (int i; i<FileNo; i++){ Serial.print(logFiles[i]); Serial.print("|"); if(i%4==0){ Serial.print("\n"); } } Serial.println("<");
Serial.printf("logFilePtr: %d, dayCtr: %d", logFilePtr, dayCtr); Serial.println(">"); return true; } }

/**** CLASS INSTANTIATION *****/

Mush_Logger mlog; void setLogType(int const log_level){ mlog.setLogLevel(log_level); }

/ The interface to this class is modeled after the Arduino_DebugUtils. It uses the esp-logger-lib found here: https://github.com/fabiuz7/esp-logger-lib for the backend In between the interface and the backend, it puts the data into csv records and performs some amount of data compression by only recording changes in the data. It also smooths the sensor data with a 3 sample moving average filter. /

ifndef MUSH_LOGGER_H

define MUSH_LOGGER_H

include

include

include

include

//note: old version of ticker library used in convience library. //csvArray defines

define COL_WIDTH 4 // 3 plus termination character

define VAL_WIDTH 9 //8 plus termination character - hh:mm:ss

define NoCol 21

// defines for file management array

define FileNo 16 // 4 days x 4 hrs each

define DayMax 365 // days in a year

// defines for how many columns of data to store

define LogInputLevel 7

define LogControlLevel 13

define LogOpsLevel 17

/***** LOG level control **/

static int const LOG_NONE = -1; //no logging static int const LOG_INPUTS = 0; // log only this level of data (e.g. sensors data) static int const LOG_CONTROLS = 1; // static int const LOG_OPS = 2; // static int const LOG_ALL = 3; // log verbose mode

void setLogType(int const log_level);

/**** CSV COLUMN NAMES *****/ extern const char COL_TMP[COL_WIDTH]; extern const char COL_HUM[COL_WIDTH]; extern const char COL_CO2[COL_WIDTH]; extern const char COL_A0I[COL_WIDTH]; extern const char COL_FSd[COL_WIDTH]; extern const char COL_OPN[COL_WIDTH]; extern const char COL_FAN[COL_WIDTH]; extern const char COL_LED[COL_WIDTH]; extern const char COL_RL1[COL_WIDTH]; extern const char COL_RL2[COL_WIDTH]; extern const char COL_RL3[COL_WIDTH]; extern const char COL_RL4[COL_WIDTH]; extern const char COL_OP1[COL_WIDTH]; extern const char COL_OP2[COL_WIDTH]; extern const char COL_OP3[COL_WIDTH]; extern const char COL_OP4[COL_WIDTH]; extern const char COL_IF1[COL_WIDTH]; extern const char COL_IF2[COL_WIDTH]; extern const char COL_IF3[COL_WIDTH]; extern const char COL_IF4[COL_WIDTH];

/***** Class Declaration **/

class Mush_Logger {

public:

Mush_Logger();

void init();
void setLogLevel(int const log_level);
void log(int const log_level, const char  *fmt, ...);
void handle();
String getLogFile(int fileID) const;
String getLogLevel()const;

private:   

// LoggerSPIFFS mushLog("/log/Mushlog.log"); int log_type; int _log_level; int logcsvlevel; void initArrays(); bool saveLogArray(); bool loadLogArray(); void lPrint(char const * fmt, va_list args); void logCSVheader(); void logCSVdata(); bool shouldLog(int const log_level) const; File loggerFile; File configFile; struct csvCell{ char colName[COL_WIDTH]; char colVal[VAL_WIDTH]; }; csvCell csvArray[NoCol];

String logFiles[FileNo]; // array for circulating log file names
int logFilePtr;
int dayCtr;

}; /** EXTERN ***/ extern Mush_Logger mlog;

endif

fabianoriccardi commented 3 years ago

Usually when you are reporting a bug you shouldn't report all your project, but only the relevant part. However, I think that the problem is in the class declaration: you missed to include LoggerSPIFFS in mush_logger.h:

#define <logger_spiffs.h>  

Moreover, you can't initiate a class member like you have done:

LoggerSPIFFS mushLog("/log/Mushlog.log");

This is wrong. You should only declare it:

LoggerSPIFFS mushLog;

And initialize the members in the constructor of MushLogger.

dduehren commented 3 years ago

Ok I’ll try it again, but I’m pretty sure I had the include for logger_SPIFFS when I was reporting the problem. I’ll get back to you. Thanks

Sent from my iPhone

David Duehren

On Mar 14, 2021, at 1:12 PM, Fabiano Riccardi @.***> wrote:

 Usually when you are reporting a bug you shouldn't report all your project, but only the relevant part. However, I think that the problem is in the class declaration: you missed to include LoggerSPIFFS in mush_logger.h:

define

Moreover, you can't initiate a class member like you have done:

LoggerSPIFFS mushLog("/log/Mushlog.log"); This is wrong. You should only declare it:

LoggerSPIFFS mushLog; And initialize the members in the constructor of MushLogger.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

dduehren commented 3 years ago

Fabiano,

I think I did what you said but it’s still not working. I’m attaching the files with the changes I made and the compiler outputs below. I’m no expert on C++ so it’s quite possible I’m doing something stupid, but I know this hasn’t gone as smoothly as the bme library which I did the same thing and followed that example closely. One main difference is that it doesn’t have an initialization variable – you pass it the i2c address in the cpp file. I’ve attached those too.

Here’s the compiler output

:\Users\DAVIDD~1\AppData\Local\Temp\arduino_build_983165\sketch\mushLogger.cpp: In constructor 'Mush_Logger::Mush_Logger()':

mushLogger.cpp:54:26: error: no matching function for call to 'LoggerSPIFFS::LoggerSPIFFS()'

Mush_Logger::Mush_Logger(){

                      ^

C:\Users\DAVIDD~1\AppData\Local\Temp\arduino_build_983165\sketch\mushLogger.cpp:54:26: note: candidates are:

In file included from C:\Users\DAVIDD~1\AppData\Local\Temp\arduino_build_983165\sketch\mushLogger.h:13:0,

             from C:\Users\DAVIDD~1\AppData\Local\Temp\arduino_build_983165\sketch\mushLogger.cpp:1:

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src/logger_spiffs.h:40:3: note: LoggerSPIFFS::LoggerSPIFFS(String, Logger::DebugLevel)

LoggerSPIFFS(String file, DebugLevel debugVerbosity = DebugLevel::ERROR);

^

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src/logger_spiffs.h:40:3: note: candidate expects 2 arguments, 0 provided

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src/logger_spiffs.h:37:7: note: LoggerSPIFFS::LoggerSPIFFS(const LoggerSPIFFS&)

class LoggerSPIFFS : public Logger{

   ^

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src/logger_spiffs.h:37:7: note: candidate expects 1 argument, 0 provided

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src/logger_spiffs.h:37:7: note: LoggerSPIFFS::LoggerSPIFFS(LoggerSPIFFS&&)

D:\David\MyDocuments\Arduino\libraries\ESP_Logger\src/logger_spiffs.h:37:7: note: candidate expects 1 argument, 0 provided

mushLogger.cpp:56:29: error: 'mushlog' was not declared in this scope

mushlog("/log/Mushlog.log");

From: Fabiano Riccardi @.> Sent: Sunday, March 14, 2021 1:12 PM To: fabiuz7/esp-logger-lib @.> Cc: David Duehren @.>; Author @.> Subject: Re: [fabiuz7/esp-logger-lib] Library incompatible with newest version of Ticker library (#9)

Usually when you are reporting a bug you shouldn't report all your project, but only the relevant part. However, I think that the problem is in the class declaration: you missed to include LoggerSPIFFS in mush_logger.h:

define

Moreover, you can't initiate a class member like you have done:

LoggerSPIFFS mushLog("/log/Mushlog.log");

This is wrong. You should only declare it:

LoggerSPIFFS mushLog;

And initialize the members in the constructor of MushLogger.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/fabiuz7/esp-logger-lib/issues/9#issuecomment-798971689 , or unsubscribe https://github.com/notifications/unsubscribe-auth/ACAY6ZZHU7TILNOOXDFAOKLTDUKBVANCNFSM4YYAHQTQ .

include "mushLogger.h"

include "Arduino_DebugUtils.h"

include

include

//extern LoggerSPIFFS mushLog; //I didn't find a way to make LoggerSPIFFS work inside a class extern NTPClient timeClient; /**** CONSTANTS **/

static int const DEFAULT_LOG_LEVEL = LOG_ALL; const char COL_TMP[COL_WIDTH] PROGMEM = "TMP"; const char COL_HUM[COL_WIDTH] PROGMEM = "HUM"; const char COL_CO2[COL_WIDTH] PROGMEM = "CO2"; const char COL_A0I[COL_WIDTH] PROGMEM = "A0I"; const char COL_FSd[COL_WIDTH] PROGMEM = "FSd"; const char COL_OPN[COL_WIDTH] PROGMEM = "OPN"; const char COL_FAN[COL_WIDTH] PROGMEM = "FAN"; const char COL_LED[COL_WIDTH] PROGMEM = "LED"; const char COL_RL1[COL_WIDTH] PROGMEM = "RL1"; const char COL_RL2[COL_WIDTH] PROGMEM = "RL2"; const char COL_RL3[COL_WIDTH] PROGMEM = "RL3"; const char COL_RL4[COL_WIDTH] PROGMEM = "RL4"; const char COL_OP1[COL_WIDTH] PROGMEM = "OP1"; const char COL_OP2[COL_WIDTH] PROGMEM = "OP2"; const char COL_OP3[COL_WIDTH] PROGMEM = "OP3"; const char COL_OP4[COL_WIDTH] PROGMEM = "OP4"; const char COL_IF1[COL_WIDTH] PROGMEM = "IF1"; const char COL_IF2[COL_WIDTH] PROGMEM = "IF2"; const char COL_IF3[COL_WIDTH] PROGMEM = "IF3"; const char COL_IF4[COL_WIDTH] PROGMEM = "IF4";

/*****

/* CTOR/DTOR **/ Mush_Logger::Mush_Logger(){ setLogLevel(DEFAULT_LOG_LEVEL); mushlog("/log/Mushlog.log"); // initArrays(); } /**** PUBLIC MEMBER FUNCTIONS *****/

void Mush_Logger::log(int const log_level, const char *fmt, ...){ Debug.print(DBG_INFO, "log method: log_level: %d", log_level); //extract the data, eventually creating a string for mushlog.append(record.c_str() if (!shouldLog(log_level)) return; String fmt_str(fmt); va_list args; va_start(args, fmt_str.c_str()); lPrint(fmt_str.c_str(), args); va_end(args); // sync inputs to the 1 second sensor logging if(log_level==LOG_INPUTS){ logCSVdata(); } }

void Mush_Logger::handle(){ // manage revolving log files. This handler should be started every 6 hours by external timer // remove current filename if(logFilePtr >= FileNo){ Debug.print(DBG_ERROR, "logFilePtr>=16!!!!!! %d", FileNo); logFilePtr = 0; } String logFileName; logFileName = logFiles[logFilePtr]; if (logFileName != "EMPTY"){ if (SPIFFS.exists(logFileName)){ if(SPIFFS.remove(logFileName)){ Debug.print(DBG_INFO, "File removed %s", logFileName.c_str()); } else { Debug.print(DBG_ERROR, "log file removal failed %s", logFileName.c_str()); } } } //create new file name logFileName = "/log/"+String(dayCtr)+String(timeClient.getHours())+String(timeClient.getMinutes())+".log"; Debug.print(DBG_INFO, "New file name %s, logFilePtr: %d", logFileName.c_str(), logFilePtr); if (SPIFFS.rename("/log/Mushlog.log",logFileName)){ logFiles[logFilePtr] = logFileName; //save new filename //presume Mushlog.log doesn't exist because it's been renamed. if (SPIFFS.exists("/log/Mushlog.log")){ Debug.print(DBG_WARNING, "Mushlog exists after renaming"); } loggerFile=SPIFFS.open("/log/Mushlog.log","a"); logCSVheader(); //add header row } else { Debug.print(DBG_ERROR, "Rename of Mushlog failed"); } // garbage collection SPIFFS.gc(); // update pointers logFilePtr++; Debug.print(DBG_INFO,"Just after logFilePtr++, logFilePtr: %d", logFilePtr); if(logFilePtr >= FileNo){ // This check is not being executed for some reason. Debug.print(DBG_INFO, "Compare to FileNo succeeded"); logFilePtr==0; } Debug.print(DBG_INFO, "Just after compare, logFilePtr: %d", logFilePtr); if ((logFilePtr % 4) == 0){ dayCtr++; } if (dayCtr > DayMax){ dayCtr=0; } // Save logArray // Because it's being saved here at 16. if(!saveLogArray()){ Debug.print(DBG_ERROR, "Saving LogArray Failed"); } }

void Mush_Logger::init(){ mushLog.begin(); mushLog.setFlusherCallback(flush); mushLog.reset(); // for now until the file management system is working mushLog.setSizeLimit(65535); //default is 1000 Serial.print("Log file size: "); Serial.println(mushLog.getSizeLimit()); mushLog.setSizeLimitPerChunk(200); // default is 100 mushLog.setOneRecordPerChunk(true); if(mushLog.getActualSize()<10){ logCSVheader(); //add header row } Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); initArrays(); / char temch[8]; for (int i=0; i<NoCol; i++){ strcpy(temch, csvArray[i].colName); Serial.print(temch); Serial.print(" : "); strcpy (temch, csvArray[i].colVal); Serial.println(temch); } / }

void Mush_Logger::setLogLevel(int const log_level){ _log_level = log_level; logcsvlevel =0; switch(_log_level){ case LOG_INPUTS: logcsvlevel=LogInputLevel; break; case LOG_CONTROLS: logcsvlevel=LogControlLevel; break; case LOG_OPS: logcsvlevel=LogOpsLevel; break; case LOG_ALL: logcsvlevel=NoCol; break; default: logcsvlevel=NoCol; break; } } String Mush_Logger::getLogFile(int fileID) const { return(logFiles[fileID]); } String Mush_Logger::getLogLevel() const { switch(_log_level){ case LOG_NONE: return("LOG_NONE"); break; case LOG_INPUTS: return("LOG_INPUTS"); break; case LOG_CONTROLS: return("LOG_CONTROLS"); break; case LOG_OPS: return("LOG_OPS"); break; case LOG_ALL: return("LOG_ALL"); break; default: return("LOG_ALL"); break; } }

/***** Private member functions **/ void Mush_Logger::initArrays(){ // Init csvArray //first set all values to "NAN"; for (int i = 0; i < NoCol; i++) { strcpy(csvArray[i].colVal, "NAN"); } strcpy(csvArray[0].colName, "TIM"); strcpy(csvArray[1].colName, COL_TMP); strcpy(csvArray[2].colName, COL_HUM); strcpy(csvArray[3].colName, COL_CO2); strcpy(csvArray[4].colName, COL_A0I); strcpy(csvArray[5].colName, COL_FSd); strcpy(csvArray[6].colName, COL_OPN); strcpy(csvArray[7].colName, COL_FAN); strcpy(csvArray[8].colName, COL_LED); strcpy(csvArray[9].colName, COL_RL1); strcpy(csvArray[10].colName, COL_RL2); strcpy(csvArray[11].colName, COL_RL3); strcpy(csvArray[12].colName, COL_RL4); strcpy(csvArray[13].colName, COL_OP1); strcpy(csvArray[14].colName, COL_OP2); strcpy(csvArray[15].colName, COL_OP3); strcpy(csvArray[16].colName, COL_OP4); strcpy(csvArray[17].colName, COL_IF1); strcpy(csvArray[18].colName, COL_IF2); strcpy(csvArray[19].colName, COL_IF3); strcpy(csvArray[20].colName, COL_IF4); /**

void Mush_Logger::lPrint(char const * fmt, va_list args){ static size_t const MSG_BUF_SIZE = 120; char msg_buf[MSG_BUF_SIZE] = {0};

vsprintf(msg_buf, fmt, args); Debug.print(DBG_INFO, "msg_buf: %s", msg_buf); // process the string into columns and values char tempCol[COL_WIDTH]; char key1=':'; char key2=','; char pcol; char pcom; char * ecol; char colTemp[COL_WIDTH]; colTemp[3]='\0'; pcom = msg_buf; ecol = strrchr(msg_buf, key1); pcol = strchr(msg_buf, key1); while (pcol!=NULL) { strncpy(colTemp, pcom, COL_WIDTH-1); if (pcol==ecol){ pcom = strchr(pcom+1, '\0'); //end of string } else { pcom = strchr(pcom+1, key2); //find comma, other way to end variable } for (int i=0; i<NoCol; i++){ if(strcmp(colTemp, csvArray[i].colName)==0){ Debug.print(DBG_VERBOSE,"Match %s", colTemp); pcol++; //point to variable strncpy(colTemp, pcol,(pcom-pcol)); if ((pcom-pcol)<3){ for(int i=(pcom-pcol); i<3; i++){ colTemp[i]='\0'; } colTemp[3]='\0'; strcpy(csvArray[i].colVal, colTemp);
} else { strncpy(csvArray[i].colVal, pcol,(pcom-pcol)); } strcpy(colTemp, csvArray[i].colVal); colTemp[3]='\0'; //reset colTemp after use for printingcol i=NoCol; // end search } else { } } // end of 4 loop pcol = strchr(pcol+1, key1); pcom++; //point to next column name } String record=""; record=""; for(int i=15; i<NoCol; i++){ record = record+csvArray[i].colVal+','; } Serial.printf("tail csvArray %s", record.c_str()); Serial.println("<>"); } void Mush_Logger::logCSVheader(){ String record=""; for(int i=0; i<logcsvlevel; i++){ if (i<logcsvlevel-1){ record = record+csvArray[i].colName+','; } else { record = record+csvArray[i].colName; } } Debug.print(DBG_INFO,"%s", record.c_str()); mushLog.append(record,0); //append adds CRLF Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); }

void Mush_Logger::logCSVdata(){ Debug.print(DBG_INFO,"logcsvlevel: %d", logcsvlevel); String record=""; record= record+timeClient.getFormattedTime()+','; for(int i=1; i<logcsvlevel; i++){ if (i<logcsvlevel-1){ record = record+csvArray[i].colVal+','; } else { record = record+csvArray[i].colVal; } } Debug.print(DBG_INFO,"%s", record.c_str()); mushLog.append(record,0); // clear array for next round for (int i = 0; i < NoCol; i++) { strcpy(csvArray[i].colVal, "NAN"); } Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); }

bool Mush_Logger::shouldLog(int const log_level) const { return((log_level > LOG_NONE) && (log_level <= LOG_ALL) && (log_level <= _log_level)); }

bool Mush_Logger::saveLogArray(){ configFile = SPIFFS.open("/logArray.txt", "w"); if (!configFile) { Debug.print(DBG_ERROR,"Failed to open logArray file for writing"); return false; } configFile.seek(0); //rewind file so test data is not appended for(int i=0; i<FileNo; i++){ configFile.print(logFiles[i]); if(i<FileNo){ configFile.print(","); } } char record[10]; snprintf(record, 10, "%d,%d,\n", logFilePtr, dayCtr); configFile.print(record); configFile.close(); Serial.println("****"); Debug.print(DBG_DEBUG, "saveLogArray"); for (int i; i<FileNo; i++){ Serial.print(logFiles[i]); Serial.print("|"); if(i%4==0){ Serial.print("\n"); } } Serial.println("<"); Serial.printf("logFilePtr: %d, dayCtr: %d", logFilePtr, dayCtr); Serial.println(">"); return true; } bool Mush_Logger::loadLogArray(){ if (SPIFFS.exists("/logArray.txt")){ File configFile = SPIFFS.open("/logArray.txt", "r"); if (!configFile) { Debug.print(DBG_ERROR, "Failed to open logArray file"); return false; } for (int i=0; i<FileNo; i++){ logFiles[i]=configFile.readStringUntil(','); } String srec = configFile.readStringUntil(','); logFilePtr=srec.toInt(); srec = configFile.readStringUntil(','); dayCtr=srec.toInt();
Serial.println("****"); Debug.print(DBG_DEBUG, "loadLogArray"); for (int i; i<FileNo; i++){ Serial.print(logFiles[i]); Serial.print("|"); if(i%4==0){ Serial.print("\n"); } } Serial.println("<");
Serial.printf("logFilePtr: %d, dayCtr: %d", logFilePtr, dayCtr); Serial.println(">"); return true; } }

/**** CLASS INSTANTIATION *****/

Mush_Logger mlog; void setLogType(int const log_level){ mlog.setLogLevel(log_level); }

/ The interface to this class is modeled after the Arduino_DebugUtils. It uses the esp-logger-lib found here: https://github.com/fabiuz7/esp-logger-lib for the backend In between the interface and the backend, it puts the data into csv records and performs some amount of data compression by only recording changes in the data. It also smooths the sensor data with a 3 sample moving average filter. /

ifndef MUSH_LOGGER_H

define MUSH_LOGGER_H

include

include

include

include

include

//note: old version of ticker library used in convience library. //csvArray defines

define COL_WIDTH 4 // 3 plus termination character

define VAL_WIDTH 9 //8 plus termination character - hh:mm:ss

define NoCol 21

// defines for file management array

define FileNo 16 // 4 days x 4 hrs each

define DayMax 365 // days in a year

// defines for how many columns of data to store

define LogInputLevel 7

define LogControlLevel 13

define LogOpsLevel 17

/***** LOG level control **/

static int const LOG_NONE = -1; //no logging static int const LOG_INPUTS = 0; // log only this level of data (e.g. sensors data) static int const LOG_CONTROLS = 1; // static int const LOG_OPS = 2; // static int const LOG_ALL = 3; // log verbose mode

void setLogType(int const log_level);

/**** CSV COLUMN NAMES *****/ extern const char COL_TMP[COL_WIDTH]; extern const char COL_HUM[COL_WIDTH]; extern const char COL_CO2[COL_WIDTH]; extern const char COL_A0I[COL_WIDTH]; extern const char COL_FSd[COL_WIDTH]; extern const char COL_OPN[COL_WIDTH]; extern const char COL_FAN[COL_WIDTH]; extern const char COL_LED[COL_WIDTH]; extern const char COL_RL1[COL_WIDTH]; extern const char COL_RL2[COL_WIDTH]; extern const char COL_RL3[COL_WIDTH]; extern const char COL_RL4[COL_WIDTH]; extern const char COL_OP1[COL_WIDTH]; extern const char COL_OP2[COL_WIDTH]; extern const char COL_OP3[COL_WIDTH]; extern const char COL_OP4[COL_WIDTH]; extern const char COL_IF1[COL_WIDTH]; extern const char COL_IF2[COL_WIDTH]; extern const char COL_IF3[COL_WIDTH]; extern const char COL_IF4[COL_WIDTH];

/***** Class Declaration **/

class Mush_Logger {

public:

Mush_Logger();

void init();
void setLogLevel(int const log_level);
void log(int const log_level, const char  *fmt, ...);
void handle();
String getLogFile(int fileID) const;
String getLogLevel()const;

private:   

LoggerSPIFFS mushLog; 
int log_type;
int _log_level;
int logcsvlevel;
void initArrays();
bool saveLogArray();
bool loadLogArray();
void lPrint(char const * fmt, va_list args);
void logCSVheader();
void logCSVdata();
bool shouldLog(int const log_level) const;
File loggerFile;
File configFile;
struct csvCell{
  char colName[COL_WIDTH];
  char colVal[VAL_WIDTH];
};
csvCell csvArray[NoCol];

String logFiles[FileNo]; // array for circulating log file names
int logFilePtr;
int dayCtr;

}; /** EXTERN ***/ extern Mush_Logger mlog;

endif

include "sensors.h"

include "Arduino_DebugUtils.h"

include "boardconfig.h"

include "mushLogger.h"

sensors sense; void sensors::init(){ aConnected = false; //default address bme280 - 0x77, SDO=GND=>0x76 if (!bme.begin(0x76)) { Debug.print(DBG_WARNING, "BME280 sensor is offline"); return; }; //bme.getLastError(); // uint8_t bme280ID = bme.readManufacturerId(); // uint8_t err = bme.getLastError(); // if (!err && bme280ID != 0x00 && bme280ID != 0xFF) { // sensor online aConnected = true; / } else { Debug.print(DBG_WARNING, "BME280 sensor offline. error: %s", String(err)); } / avgPtr=0; } void sensors::setMode(int tmode){ ltempMode = 0; if (tmode>0) ltempMode = 1; } int sensors::getMode() const { return ltempMode; } void sensors::handle(){ th_handle(); co2_handle(); gas_handle(); // manage pointer and send info avgPtr++; if(avgPtr >= maSize){ avgPtr = 0; mlog.log(LOG_INPUTS, "%s:%3.2f,%s:%2.2f,%s:%6.1f,%s:%5.1f",COL_TMP,Temperature,COL_HUM,Humidity,COL_CO2,CO2Lvl,COL_A0I,GasLvl);
} }

void sensors::th_handle(){ float t = bme.readTemperature(); float h = bme.readHumidity(); aConnected = true; tempArr[avgPtr] = t; humArr[avgPtr] = h; t = (tempArr[0] + tempArr[1] + tempArr[2])/3; if (ltempMode>0){ Temperature = 32+t*9/5; } else { Temperature = t; } Humidity = (humArr[0] + humArr[1] + humArr[2])/3; if(isnan(Humidity) || isnan(Temperature)){ init(); } Debug.print(DBG_INFO, "Humidity %5.2f%, Celcius Temp %4.1f degrees, Temperature %4.1f degrees", h, t, Temperature); }

void sensors::co2_handle(){ float co2; if(BD_VER < 3){ int sensorValue = analogRead(adcPin); co2 = sensorValue*(5000/639.0); //upper value is 5000pm, 3.3V to 1V scaling of 2V upper CO2 sensor level on 1023 leads to 639 as upper value. co2Arr[avgPtr]=co2; if(co2 < 1){ Debug.print(DBG_ERROR, "CO2 sensor Fault"); } else { if ((co2>1) && (co2< 127)) { Debug.print(DBG_WARNING, "CO2 sensor pre-heating"); } } CO2Lvl = (co2Arr[0] + co2Arr[1] + co2Arr[2])/3; } else { //TBD = i2c based } } void sensors::gas_handle(){ float gas; if(BD_VER < 3){ gas = analogRead(adcPin); gasArr[avgPtr] = gas; GasLvl = (gasArr[0] + gasArr[1] + gasArr[2])/3; } else { // TBD } }

bool sensors::connected() { return aConnected; } float sensors::getHumidity() const{ return Humidity; } float sensors::getTemp() const{ return Temperature; } float sensors::getCO2() const{ return CO2Lvl; } float sensors::getGas() const { // basically raw ADC reading.
return GasLvl; }

ifndef SENSORS_H

define SENSORS_H

// Code borrowed from: https://github.com/merlokk/SmartHome/blob/master/lib/BME280.cpp and ...BME280.h

include "Arduino.h"

include

include // original: https://github.com/adafruit/Adafruit_BME280_Library

                            // with error handling fix: https://github.com/merlokk/Adafruit_BME280_Library

include "Arduino_DebugUtils.h"

define maSize 3 //moving avearge array size

class sensors{ public: void init(); void handle(); bool connected(); void setMode(int tmode); int getMode() const; float getTemp() const; float getHumidity() const; float getCO2() const; float getGas() const;

private: Adafruit_BME280 bme; bool aConnected = false; float Temperature; float Humidity; float CO2Lvl; float GasLvl; int ltempMode; int trainStop;

float tempArr[maSize] = {0,0,0}; float humArr[maSize] = {0,0,0}; float co2Arr[maSize] = {0,0,0}; float gasArr[maSize] = {0,0,0}; int avgPtr; //arrays can share the pointer void th_handle(); void co2_handle(); void gas_handle();

}; extern sensors sense;

endif SENSORS_H

fabianoriccardi commented 3 years ago

In this case, you have to know what initializer list is (you can search on google). Basically you must initialize all the members that do not have a default constructor (like LoggerSPIFFS) at the begin of your constructor. Example:

Mush_Logger::Mush_Logger(): mushLog("path/to/file"){ // Your code }

fabianoriccardi commented 3 years ago

I found out a bit of time to revise this library... I think I will integrate a circular logger in next release.

dduehren commented 3 years ago

Hi Fabiano,

I can send you my code for a circular logger in exchange if you figure put SPIFFSlogger in my code and get it to work.

Sent from my iPhone

David Duehren

On Mar 28, 2021, at 1:10 PM, Fabiano Riccardi @.***> wrote:

 I found out a bit of time to revise this library... I think I will integrate a circular logger in next release.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

dduehren commented 3 years ago

Fabianno,

If you want to borrow any code from feel free. I’m semi-retired and never was a software engineer though I’ve written some code in my career. I’m slowly coming up the learning curve on C++ and that may be why I haven’t gotten your library to work in my Class directly. As you can see I’m using an external for it.

I have an array based circular logging buffer that I can upload via the web interface I’ve implemented. You may want a better file naming technique, etc. But I also store the array pointer and the array to SPIFFS so if the system is shut down it can start back up where it left off.

And if you want to comment on better coding etc feel free.

Thanks,

David

From: Fabiano Riccardi @.> Sent: Sunday, March 28, 2021 1:11 PM To: fabiuz7/esp-logger-lib @.> Cc: David Duehren @.>; Author @.> Subject: Re: [fabiuz7/esp-logger-lib] Library incompatible with newest version of Ticker library (#9)

I found out a bit of time to revise this library... I think I will integrate a circular logger in next release.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/fabiuz7/esp-logger-lib/issues/9#issuecomment-808952282 , or unsubscribe https://github.com/notifications/unsubscribe-auth/ACAY6Z25QTHA6KXFB4UHU63TF6LNPANCNFSM4YYAHQTQ .

include "mushLogger.h"

include "Arduino_DebugUtils.h"

include

include "shroom.h"

include

include

extern LoggerSPIFFS mushLog; //I didn't find a way to make LoggerSPIFFS work inside a class extern FS SPIFFS; extern NTPClient timeClient; /**** CONSTANTS **/

static int const DEFAULT_LOG_LEVEL = LOG_ALL; const char COL_TMP[COL_WIDTH] PROGMEM = "TMP"; const char COL_HUM[COL_WIDTH] PROGMEM = "HUM"; const char COL_CO2[COL_WIDTH] PROGMEM = "CO2"; const char COL_A0I[COL_WIDTH] PROGMEM = "A0I"; const char COL_FSd[COL_WIDTH] PROGMEM = "FSd"; const char COL_OPN[COL_WIDTH] PROGMEM = "OPN"; const char COL_FAN[COL_WIDTH] PROGMEM = "FAN"; const char COL_LED[COL_WIDTH] PROGMEM = "LED"; const char COL_RL1[COL_WIDTH] PROGMEM = "RL1"; const char COL_RL2[COL_WIDTH] PROGMEM = "RL2"; const char COL_RL3[COL_WIDTH] PROGMEM = "RL3"; const char COL_RL4[COL_WIDTH] PROGMEM = "RL4"; const char COL_OP1[COL_WIDTH] PROGMEM = "OP1"; const char COL_OP2[COL_WIDTH] PROGMEM = "OP2"; const char COL_OP3[COL_WIDTH] PROGMEM = "OP3"; const char COL_OP4[COL_WIDTH] PROGMEM = "OP4"; const char COL_IF1[COL_WIDTH] PROGMEM = "IF1"; const char COL_IF2[COL_WIDTH] PROGMEM = "IF2"; const char COL_IF3[COL_WIDTH] PROGMEM = "IF3"; const char COL_IF4[COL_WIDTH] PROGMEM = "IF4";

/*****

/* CTOR/DTOR **/ Mush_Logger::Mush_Logger(){ setLogLevel(DEFAULT_LOG_LEVEL); // mushlog("/log/Mushlog.log"); // initArrays(); } /**** PUBLIC MEMBER FUNCTIONS *****/

void Mush_Logger::log(int const log_level, const char *fmt, ...){ Debug.print(DBG_INFO, "log method: log_level: %d", log_level); //extract the data, eventually creating a string for mushlog.append(record.c_str() if (!shouldLog(log_level)) return; String fmt_str(fmt); va_list args; va_start(args, fmt_str.c_str()); lPrint(fmt_str.c_str(), args); va_end(args); // sync inputs to the 1 second sensor logging if(log_level==LOG_INPUTS){ logCSVdata(); } }

void Mush_Logger::handle(){ // manage revolving log files. This handler should be started every 6 hours by external timer // remove current filename if(logFilePtr >= FileNo){ Debug.print(DBG_ERROR, "logFilePtr>=16!!!!!! %d", FileNo); logFilePtr = 0; } String logFileName; logFileName = logFiles[logFilePtr]; if (logFileName != "EMPTY"){ if (SPIFFS.exists(logFileName)){ if(SPIFFS.remove(logFileName)){ Debug.print(DBG_INFO, "File removed %s", logFileName.c_str()); } else { Debug.print(DBG_ERROR, "log file removal failed %s", logFileName.c_str()); } } } //create new file name logFileName = "/log/"+String(shroom.getDayCount())+String(timeClient.getHours())+String(timeClient.getMinutes())+".log"; Debug.print(DBG_INFO, "New file name %s, logFilePtr: %d", logFileName.c_str(), logFilePtr); if (SPIFFS.rename("/log/Mushlog.log",logFileName)){ logFiles[logFilePtr] = logFileName; //save new filename //presume Mushlog.log doesn't exist because it's been renamed. if (SPIFFS.exists("/log/Mushlog.log")){ Debug.print(DBG_WARNING, "Mushlog exists after renaming"); } loggerFile=SPIFFS.open("/log/Mushlog.log","a"); logCSVheader(); //add header row } else { Debug.print(DBG_ERROR, "Rename of Mushlog failed"); } // garbage collection SPIFFS.gc(); // update pointers logFilePtr++; Debug.print(DBG_INFO,"Just after logFilePtr++, logFilePtr: %d", logFilePtr); if(logFilePtr >= FileNo){ // This check is not being executed for some reason. Debug.print(DBG_INFO, "Compare to FileNo succeeded"); logFilePtr==0; } Debug.print(DBG_INFO, "Just after compare, logFilePtr: %d", logFilePtr);

// Save logArray                // Because it's being saved here at 16.
 if(!saveLogArray()){
  Debug.print(DBG_ERROR, "Saving LogArray Failed");
  }

}

void Mush_Logger::init(){ mushLog.begin(); mushLog.setFlusherCallback(flush); //mushLog.reset(); // for now until the file management system is working mushLog.setSizeLimit(65535); //default is 1000 Serial.print("Log file size: "); Serial.println(mushLog.getSizeLimit()); mushLog.setSizeLimitPerChunk(200); // default is 100 mushLog.setOneRecordPerChunk(true); if(mushLog.getActualSize()<10){ logCSVheader(); //add header row } Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); initArrays(); / char temch[8]; for (int i=0; i<NoCol; i++){ strcpy(temch, csvArray[i].colName); Serial.print(temch); Serial.print(" : "); strcpy (temch, csvArray[i].colVal); Serial.println(temch); } / }

void Mush_Logger::setLogLevel(int const log_level){ _log_level = log_level; logcsvlevel =0; switch(_log_level){ case LOG_INPUTS: logcsvlevel=LogInputLevel; break; case LOG_CONTROLS: logcsvlevel=LogControlLevel; break; case LOG_OPS: logcsvlevel=LogOpsLevel; break; case LOG_ALL: logcsvlevel=NoCol; break; default: logcsvlevel=NoCol; break; } } String Mush_Logger::getLogFile(int fileID) const { return(logFiles[fileID]); } String Mush_Logger::getLogLevel() const { switch(_log_level){ case LOG_NONE: return("LOG_NONE"); break; case LOG_INPUTS: return("LOG_INPUTS"); break; case LOG_CONTROLS: return("LOG_CONTROLS"); break; case LOG_OPS: return("LOG_OPS"); break; case LOG_ALL: return("LOG_ALL"); break; default: return("LOG_ALL"); break; } }

/***** Private member functions **/ void Mush_Logger::initArrays(){ // Init csvArray //first set all values to "NAN"; for (int i = 0; i < NoCol; i++) { strcpy(csvArray[i].colVal, "NAN"); } strcpy(csvArray[0].colName, "TIM"); strcpy(csvArray[1].colName, COL_TMP); strcpy(csvArray[2].colName, COL_HUM); strcpy(csvArray[3].colName, COL_CO2); strcpy(csvArray[4].colName, COL_A0I); strcpy(csvArray[5].colName, COL_FSd); strcpy(csvArray[6].colName, COL_OPN); strcpy(csvArray[7].colName, COL_FAN); strcpy(csvArray[8].colName, COL_LED); strcpy(csvArray[9].colName, COL_RL1); strcpy(csvArray[10].colName, COL_RL2); strcpy(csvArray[11].colName, COL_RL3); strcpy(csvArray[12].colName, COL_RL4); strcpy(csvArray[13].colName, COL_OP1); strcpy(csvArray[14].colName, COL_OP2); strcpy(csvArray[15].colName, COL_OP3); strcpy(csvArray[16].colName, COL_OP4); strcpy(csvArray[17].colName, COL_IF1); strcpy(csvArray[18].colName, COL_IF2); strcpy(csvArray[19].colName, COL_IF3); strcpy(csvArray[20].colName, COL_IF4); /**

void Mush_Logger::lPrint(char const * fmt, va_list args){ static size_t const MSG_BUF_SIZE = 120; char msg_buf[MSG_BUF_SIZE] = {0};

vsprintf(msg_buf, fmt, args); Debug.print(DBG_VERBOSE, "msg_buf: %s", msg_buf); // process the string into columns and values char tempCol[COL_WIDTH]; char key1=':'; char key2=','; char pcol; char pcom; char * ecol; char colTemp[COL_WIDTH]; colTemp[3]='\0'; pcom = msg_buf; ecol = strrchr(msg_buf, key1); pcol = strchr(msg_buf, key1); while (pcol!=NULL) { strncpy(colTemp, pcom, COL_WIDTH-1); if (pcol==ecol){ pcom = strchr(pcom+1, '\0'); //end of string } else { pcom = strchr(pcom+1, key2); //find comma, other way to end variable } for (int i=0; i<NoCol; i++){ if(strcmp(colTemp, csvArray[i].colName)==0){ Debug.print(DBG_VERBOSE,"Match %s", colTemp); pcol++; //point to variable strncpy(colTemp, pcol,(pcom-pcol)); if ((pcom-pcol)<3){ for(int i=(pcom-pcol); i<3; i++){ colTemp[i]='\0'; } colTemp[3]='\0'; strcpy(csvArray[i].colVal, colTemp);
} else { strncpy(csvArray[i].colVal, pcol,(pcom-pcol)); } strcpy(colTemp, csvArray[i].colVal); colTemp[3]='\0'; //reset colTemp after use for printingcol i=NoCol; // end search } else { } } // end of 4 loop pcol = strchr(pcol+1, key1); pcom++; //point to next column name } String record=""; record=""; for(int i=15; i<NoCol; i++){ record = record+csvArray[i].colVal+','; } // Serial.printf("tail csvArray %s", record.c_str()); // Serial.println("<>"); } void Mush_Logger::logCSVheader(){ String record=""; for(int i=0; i<logcsvlevel; i++){ if (i<logcsvlevel-1){ record = record+csvArray[i].colName+','; } else { record = record+csvArray[i].colName; } } Debug.print(DBG_INFO,"%s", record.c_str()); mushLog.append(record,0); //append adds CRLF Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); }

void Mush_Logger::logCSVdata(){ Debug.print(DBG_INFO,"logcsvlevel: %d", logcsvlevel); String record=""; record= record+timeClient.getFormattedTime()+','; for(int i=1; i<logcsvlevel; i++){ if (i<logcsvlevel-1){ record = record+csvArray[i].colVal+','; } else { record = record+csvArray[i].colVal; } } Debug.print(DBG_INFO,"%s", record.c_str()); mushLog.append(record,0); // clear array for next round for (int i = 0; i < NoCol; i++) { strcpy(csvArray[i].colVal, "NAN"); } Serial.print("Log file size: "); Serial.println(mushLog.getActualSize()); }

bool Mush_Logger::shouldLog(int const log_level) const { return((log_level > LOG_NONE) && (log_level <= LOG_ALL) && (log_level <= _log_level)); }

bool Mush_Logger::saveLogArray(){ configFile = SPIFFS.open("/logArray.txt", "w"); if (!configFile) { Debug.print(DBG_ERROR,"Failed to open logArray file for writing"); return false; } configFile.seek(0); //rewind file so test data is not appended for(int i=0; i<FileNo; i++){ configFile.print(logFiles[i]); if(i<FileNo){ configFile.print(","); } } char record[10]; snprintf(record, 10, "%d,\n", logFilePtr); configFile.print(record); configFile.close(); Serial.println("****"); Debug.print(DBG_DEBUG, "saveLogArray"); for (int i; i<FileNo; i++){ Serial.print(logFiles[i]); Serial.print("|"); if(i%4==0){ Serial.print("\n"); } } Serial.println("<"); Serial.printf("logFilePtr: %d", logFilePtr); Serial.println(">"); return true; } bool Mush_Logger::loadLogArray(){ if (SPIFFS.exists("/logArray.txt")){ File configFile = SPIFFS.open("/logArray.txt", "r"); if (!configFile) { Debug.print(DBG_ERROR, "Failed to open logArray file"); return false; } for (int i=0; i<FileNo; i++){ logFiles[i]=configFile.readStringUntil(','); } String srec = configFile.readStringUntil(','); logFilePtr=srec.toInt();
Serial.println("****"); Debug.print(DBG_DEBUG, "loadLogArray"); for (int i; i<FileNo; i++){ Serial.print(logFiles[i]); Serial.print("|"); if(i%4==0){ Serial.print("\n"); } } Serial.println("<");
Serial.printf("logFilePtr: %d", logFilePtr); Serial.println(">"); return true; } }

/**** CLASS INSTANTIATION *****/

Mush_Logger mlog; void setLogType(int const log_level){ mlog.setLogLevel(log_level); }

/ The interface to this class is modeled after the Arduino_DebugUtils. It uses the esp-logger-lib found here: https://github.com/fabiuz7/esp-logger-lib for the backend In between the interface and the backend, it puts the data into csv records and performs some amount of data compression by only recording changes in the data. It also smooths the sensor data with a 3 sample moving average filter. /

ifndef MUSH_LOGGER_H

define MUSH_LOGGER_H

include

include

include

include

//note: old version of ticker library used in convience library. //csvArray defines

define COL_WIDTH 4 // 3 plus termination character

define VAL_WIDTH 9 //8 plus termination character - hh:mm:ss

define NoCol 21

// defines for file management array

define FileNo 16 // 4 days x 4 hrs each

define DayMax 365 // days in a year

// defines for how many columns of data to store

define LogInputLevel 7

define LogControlLevel 13

define LogOpsLevel 17

/***** LOG level control **/

static int const LOG_NONE = -1; //no logging static int const LOG_INPUTS = 0; // log only this level of data (e.g. sensors data) static int const LOG_CONTROLS = 1; // static int const LOG_OPS = 2; // static int const LOG_ALL = 3; // log verbose mode

void setLogType(int const log_level);

/**** CSV COLUMN NAMES *****/ extern const char COL_TMP[COL_WIDTH]; extern const char COL_HUM[COL_WIDTH]; extern const char COL_CO2[COL_WIDTH]; extern const char COL_A0I[COL_WIDTH]; extern const char COL_FSd[COL_WIDTH]; extern const char COL_OPN[COL_WIDTH]; extern const char COL_FAN[COL_WIDTH]; extern const char COL_LED[COL_WIDTH]; extern const char COL_RL1[COL_WIDTH]; extern const char COL_RL2[COL_WIDTH]; extern const char COL_RL3[COL_WIDTH]; extern const char COL_RL4[COL_WIDTH]; extern const char COL_OP1[COL_WIDTH]; extern const char COL_OP2[COL_WIDTH]; extern const char COL_OP3[COL_WIDTH]; extern const char COL_OP4[COL_WIDTH]; extern const char COL_IF1[COL_WIDTH]; extern const char COL_IF2[COL_WIDTH]; extern const char COL_IF3[COL_WIDTH]; extern const char COL_IF4[COL_WIDTH];

/***** Class Declaration **/

class Mush_Logger {

public:

Mush_Logger();

void init();
void setLogLevel(int const log_level);
void log(int const log_level, const char  *fmt, ...);
void handle();
String getLogFile(int fileID) const;
String getLogLevel()const;

private:   

// LoggerSPIFFS mushLog; int log_type; int _log_level; int logcsvlevel; void initArrays(); bool saveLogArray(); bool loadLogArray(); void lPrint(char const * fmt, va_list args); void logCSVheader(); void logCSVdata(); bool shouldLog(int const log_level) const; File loggerFile; File configFile; struct csvCell{ char colName[COL_WIDTH]; char colVal[VAL_WIDTH]; }; csvCell csvArray[NoCol];

String logFiles[FileNo]; // array for circulating log file names
int logFilePtr;

}; /** EXTERN ***/ extern Mush_Logger mlog;

endif

fabianoriccardi commented 3 years ago

Hi thanks for availability. I have already started to write a skeleton of the library, and I can see some similarity with yours.

I will extend the virtual class Logger with a "Logger Rotate" class (or something similar) to make this extension more coherent to the rest of the library.