ESP32 - problem with asynch web server and server sent events (title edited)

I'm counting pulses from an electricity meter using an ESP32 DEVKIT and an ISR to increment a variable.
I'm seeing errors like this:

E (17121869) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (17121869) task_wdt: - IDLE0 (CPU 0)
E (17121869) task_wdt: Tasks currently running:
E (17121869) task_wdt: CPU 0: wifi
E (17121869) task_wdt: CPU 1: loopTask
E (17121869) task_wdt: Aborting.

I'm wondering if my loop() is placing an unnecessary demand on the ESP32. Basically it repeatedly checks a set of conditions that will not change too often - so there would be room to allow the ESP to do some housekeeping, eg by adding a short delay() between loops.

void loop() {
  ftpSrv.handleFTP();        //make sure in loop you call handleFTP()!!
  //pollInput();            //alternative for testing without interrupt
  PulseState = digitalRead(intPin); //reflect input pulse to LED
  digitalWrite(LED_Pulse, (PulseState + 1) % 2); //because input active low
  /*  *** members of timeinfo structure access as eg timeinfo.tm_yday for day number of year
    int    tm_sec   seconds [0,61]; int    tm_min   minutes [0,59]; int    tm_hour  hour [0,23]; int    tm_mday  day of month [1,31]
    int    tm_mon   month of year [0,11]; int    tm_year  years since 1900; int    tm_wday  day of week [0,6] (Sunday = 0)
    int    tm_yday  day of year [0,365]; int    tm_isdst daylight savings flag
  */
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return;
  }
  if (!fileNameSet ) {
    // if its not yet been set - maybe reset of time failed?
    newMonth(); //no file exists as yet so create one and
    currMonth = timeinfo.tm_mon; //update current month
  }

  checkPeriod(); //record current, previous, max values of watts

  if (timeinfo.tm_mday != currDay) {
    //start of new day
    newDay(); //save day data to file
    currDay = timeinfo.tm_mday; //update current day
  }

  if (timeinfo.tm_mon != currMonth) {
    //start of new month
    newMonth();
    currMonth = timeinfo.tm_mon; //update current month
  }
  
  buildDate();

   if ((millis() - lastTime) > timerDelay) {
    
    // Send Events to the Web Server with the Sensor Readings
    events.send("ping",NULL,millis());
    events.send(String(myDate).c_str(),"time",millis());
    events.send(String(dTotalkWh).c_str(),"dtotal",millis());
    events.send(String(yTotalkWh).c_str(),"ytotal",millis());
    events.send(String(pWatts).c_str(),"pwatts",millis());
    events.send(String(mWatts).c_str(),"mwatts",millis());
    events.send(String(cWatts).c_str(),"cwatts",millis());
    
    lastTime = millis();
  }

} //end of loop

in an ESP32 completing the loop will reset the watchdog counter. So if the watchdog got triggered it means your loop does not complete fast enough

you could also be forever stuck in the ISR and never go back to the loop, or dead in the setup etc... post the full code -> Don't post snippets (Snippets R Us!)

sprinkling yield() statements in your various loops( for loops etc.) might help. However, you've probably got a for loop or similar which never meets its end condition.

loop() can't run "too fast". In fact you want to design your program to run loop() as fast as possible because every iteration of loop() resets the WDT.

You typically get a WDT crash if you have blocking code in your program. Since you did not post the complete code there is no way I could evaluate where the blocking is occurring.

A delay() between loops would not help because ending and restarting loop() resets the WDT anyway.

If you can identify the blocking code you may be able to insert a yield() to reset the WDT. But since you didn't post all of the code, I can't help you.

Yes, I'd also be interested in seeing the complete code that causes WDT crash.

I've never gotten Core 1 to WDT crash even when I tried to intentionally (as a learning experiment). I've locked Core 1 in task running at highest possible priority and executing a tight loop. This should allow no other task to run as preemption on FreeRTOS ticks should only fire up a task of equal or higher priority to possibly tickle the WDT. Thus, I don't see why there isn't a WDT interrupt/crash. So, like I said, I'm interested in how OP managed to do it.

See this thread: https://forum.arduino.cc/t/why-cant-i-wdt-crash-esp32-core-1/865718

@J-M-L , @6v6gt @SteveMann @gfvalvo
Thanks for your interest. I've attached the complete code. Does the watchdog message indicate the error is on CPU0 - which seems to be handling the wifi?

To add a bit more information these errors seem to occur very infrequently - I'm having to run connected to a linux laptop & putty serial monitor for a period of several days to check stability.
Its just crashed with the guru meditation error after 4 days of running fine.

Also I more often see them when connected to my "arduino" PC, with the IDE running & using the serial monitor. And often soon after a reset, but well after the setup() has completed.

the "watchdog" message - complete - was
E (17116869) wifi:lmac.c lmacTxDone 1956

E (17121869) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (17121869) task_wdt: - IDLE0 (CPU 0)
E (17121869) task_wdt: Tasks currently running:
E (17121869) task_wdt: CPU 0: wifi
E (17121869) task_wdt: CPU 1: loopTask
E (17121869) task_wdt: Aborting.
abort() was called at PC 0x40144bec on core 0

ELF file SHA256: 0000000000000000

Backtrace: 0x40088800:0x3ffbf840 0x40088a7d:0x3ffbf860 0x40144bec:0x3ffbf880 0x40086fc9:0x3ffbf8a0 0x4010a852:0x3ffb5740 0x4010b761:0x3ffb5770 0x4010c05d:0x3ffb57b0 0x4010c169:0x3ffb57e0 0x40110977:0x3ffb5810 0x40089a8e:0x3ffb5840

Rebooting...
ets Jun 8 2016 00:22:57

I've also had

Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400d7fc6 PS : 0x00060230 A0 : 0x800d8066 A1 : 0x3ffb1ef0
A2 : 0x3ffbbe7c A3 : 0x000e0b01 A4 : 0x00008100 A5 : 0x3ffd2e4c
A6 : 0x3036203a A7 : 0x0a0d0a0d A8 : 0x00008100 A9 : 0x3ffb1ed0
A10 : 0x30333033 A11 : 0x3ffd2ff0 A12 : 0x00000028 A13 : 0x00000028
A14 : 0x00000000 A15 : 0x000a0d0a SAR : 0x0000000a EXCCAUSE: 0x0000001c
EXCVADDR: 0x000e0b01 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff

ELF file SHA256: 0000000000000000

Backtrace: 0x400d7fc6:0x3ffb1ef0 0x400d8063:0x3ffb1f10 0x400d8083:0x3ffb1f30 0x400d80d9:0x3ffb1f50 0x400d1921:0x3ffb1f80 0x400df275:0x3ffb1fb0 0x40089a8e:0x3ffb1fd0

Decoding 7 results
0x400d7fc6: AsyncEventSourceClient::_runQueue() at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d8063: AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage*) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d8083: AsyncEventSourceClient::write(char const*, unsigned int) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d80d9: AsyncEventSource::send(char const*, char const*, unsigned int, unsigned int) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d1921: loop() at C:\ArduinoIDEPortable\portable\sketchbook\ESP32\SolarLoggerFinal3/wifi.ino line 12
0x400df275: loopTask(void*) at C:\ArduinoIDEPortable\portable\packages\esp32\hardware\esp32\1.0.6\cores\esp32/main.cpp line 23
0x40089a8e: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 355 (discriminator 1)

datavalues.ino (3.5 KB)
SolarLogger.h (7.1 KB)
SolarLoggerJune3.ino (5.0 KB)
spiffs.ino (704 Bytes)
webpage.ino (1.1 KB)
wifi.ino (876 Bytes)

What were the results when you ran it through the Exception Stack Trace Decoder?

The "watchdog" message was shown when I was recording serial output to file on a laptop. The results from the

dont appear to make any sense, and maybe reflect the later guru error that showed when I was using the IDE.


0x40088800: doBacktrace at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 715
0x40088a7d: xPortGetCoreID at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 715
:  (inlined by) abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 163
0x40144bec: task_wdt_isr at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/task_wdt.c line 252
0x40086fc9: _xt_lowint1 at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/xtensa_vectors.S line 1154
0x4010a852: ic_csi_set_config at ?? line ?
0x4010b761: lmacTxFrame at ?? line ?
0x4010c05d: lmacProcessTxSuccess at ?? line ?
0x4010c169: lmacProcessTxComplete at ?? line ?
0x40110977: ppTask at ?? line ?
0x40089a8e: _xt_tick_divisor_init at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/xtensa_init.c line 45

I've just had another guru error!

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d7f42  PS      : 0x00060230  A0      : 0x800d7fe2  A1      : 0x3ffb1ef0  
A2      : 0x3ffce084  A3      : 0x06ff0000  A4      : 0x00000027  A5      : 0x3ffd33c6  
A6      : 0x0000000a  A7      : 0x61746164  A8      : 0x800d7f50  A9      : 0x3ffb1ed0  
A10     : 0x00000027  A11     : 0x00000047  A12     : 0x00000027  A13     : 0x00000027  
A14     : 0x00000000  A15     : 0x00000020  SAR     : 0x0000000a  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x06ff0000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  

ELF file SHA256: 0000000000000000

Backtrace: 0x400d7f42:0x3ffb1ef0 0x400d7fdf:0x3ffb1f10 0x400d7fff:0x3ffb1f30 0x400d8055:0x3ffb1f50 0x400d1826:0x3ffb1f80 0x400df1d5:0x3ffb1fb0 0x40089aae:0x3ffb1fd0

Rebooting...

the decoder says

Decoding 7 results
0x400d7f42: AsyncEventSourceClient::_runQueue() at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d7fdf: AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage*) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d7fff: AsyncEventSourceClient::write(char const*, unsigned int) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d8055: AsyncEventSource::send(char const*, char const*, unsigned int, unsigned int) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d1826: loop() at C:\ArduinoIDEPortable\portable\sketchbook\ESP32\SolarLoggerJune3/SolarLoggerJune3.ino line 132
0x400df1d5: loopTask(void*) at C:\ArduinoIDEPortable\portable\packages\esp32\hardware\esp32\1.0.6\cores\esp32/main.cpp line 23
0x40089aae: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 355 (discriminator 1)

I've just noticed this in wifi.ino

void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
  Serial.println("WiFi connected - IP address: ");
  Serial.println(WiFi.localIP());
}

and this from the dump

[quote="johnerrington, post:6, topic:870010"]
0x400d1921: loop() at C:\ArduinoIDEPortable\portable\sketchbook\ESP32\SolarLoggerFinal3/wifi.ino line 12
[/quote]

It appears Serial.print is not liked in this context.

You could also try forcing the event handlers to stay in RAM with this attribute: IRAM_ATTR

.

Further, this dump entry :

0x400d1826: loop() at C:\ArduinoIDEPortable\portable\sketchbook\ESP32\SolarLoggerJune3/SolarLoggerJune3.ino line 132

appears to refer to this code line (or near):

 events.send(String(pWatts).c_str(),"pwatts",millis());

I can't immediately follow it back, but if this is asynchronous, that is the data is queued somewhere before being processed, the String may have vanished before an attempt is made to handle it. The reference page to the c_str() method also warns explicitly about this.

How?? do you determine that?

The OP included all source code in an earlier post.

Thanks @6v6gt your interpretation has helped me make a bit of sense of the GME Exception decoder output.
I tried again having stripped out the serial prints from the event handlers, and added the IRAM_ATTR; however I soon got another Guru error that appears to relate to this line

    events.send(String(cWatts).c_str(), "cwatts", millis());


Decoding 7 results
0x400d7f32: AsyncEventSourceClient::_runQueue() at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d7fcf: AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage*) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d7fef: AsyncEventSourceClient::write(char const*, unsigned int) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d8045: AsyncEventSource::send(char const*, char const*, unsigned int, unsigned int) at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858
0x400d1849: loop() at C:\ArduinoIDEPortable\portable\sketchbook\ESP32\SolarLoggerJune6/SolarLoggerJune6.ino line 141
0x400df1f5: loopTask(void*) at C:\ArduinoIDEPortable\portable\packages\esp32\hardware\esp32\1.0.6\cores\esp32/main.cpp line 23
0x40089afa: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 355 (discriminator 1)

cWatts was getting updated in the ISR - so I changed it to update in loop() just before it gets used to update the web page via the line of code above. Same error again.
So I commented out events.send(String(cWatts).c_str(), "cwatts", millis());
and the next error was on the line above - events.send(String(mWatts).c_str(), "mwatts", millis());

then a little later another relating to the line above - events.send(String(pWatts).c_str(), "pwatts", millis());

It REALLY doesnt like that events.send method in the async web server.

I have two units using the async web server with no issues - why is this one being such a ... (expletive deleted)

To save me hunting through all your code, where is the events object instantiated ?

But I'm guessing that the problem is that the object returned by the c_str() method is not there at the time the reference to it is to be resolved.
As a quick test, I'd create a global character array, say testBuff[6], and put "hello" in it. Then in such statements : events.send(String(cWatts).c_str(), "cwatts", millis());
replace that String with &testBuff[ 0 ] just to see if the problem goes away.

in SolarLogger.h

AsyncWebServer server(80); // Set web server port number to 80
AsyncEventSource events("/events");  // Create an Event Source on /events

then in setup()



  // Handle Web Server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/html", index_html, processor);
  });

  // Handle Web Server Events
  events.onConnect([](AsyncEventSourceClient * client) {
    if (client->lastId()) {
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 1000);
  });
  server.addHandler(&events);
  server.begin(); //start web server

in the web page

<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');
 
 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);
 
 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);
 
 source.addEventListener('time', function(e) {
  console.log("time", e.data);
  document.getElementById("time").innerHTML = e.data;
 }, false);
 
 source.addEventListener('dtotal', function(e) {
  console.log("dtotal", e.data);
  document.getElementById("dtotal").innerHTML = e.data;
 }, false);
 
 source.addEventListener('ytotal', function(e) {
  console.log("ytotal", e.data);
  document.getElementById("ytotal").innerHTML = e.data;
 }, false);
 
 source.addEventListener('pwatts', function(e) {
  console.log("pwatts", e.data);
  document.getElementById("pwatts").innerHTML = e.data;
 }, false);
 
 source.addEventListener('mwatts', function(e) {
  console.log("mwatts", e.data);
  document.getElementById("mwatts").innerHTML = e.data;
 }, false);
 
 source.addEventListener('cwatts', function(e) {
  console.log("cwatts", e.data);
  document.getElementById("cwatts").innerHTML = e.data;
 }, false);
 
}
</script>

.. and the event processor

String processor(const String& var){
  if(var == "TIME"){
    return String(myDate);
  }
  else if(var == "DTOTAL"){
    return String(dTotalkWh);
  }
  else if(var == "YTOTAL"){
    return String(yTotalkWh);
  }
  else if(var == "PWATTS"){
    return String(pWatts);
  }
  else if(var == "MWATTS"){
    return String(mWatts);
  }
  else if(var == "CWATTS"){
    return String(cWatts);
  }
  return String();
}

I've commented out all those as shown below - I used char testBuff[8] = "testing"; as I already had a "hello"


    // Send Events to the Web Server with the Sensor Readings
    events.send("ping", NULL, millis());
    //events.send(String(myDate).c_str(), "time", millis());
    //events.send(String(dTotalkWh).c_str(), "dtotal", millis());
    //events.send(String(yTotalkWh).c_str(), "ytotal", millis());
    //events.send(String(pWatts).c_str(), "pwatts", millis());
    //events.send(String(mWatts).c_str(), "mwatts", millis());
    //events.send(String(cWatts).c_str(), "cwatts", millis());
    events.send( &testBuff[ 0 ], "cwatts", millis());

Now it shows "testing" when it auto-updates, but still shows the actual values (presumably from processor(); ) when I refresh.

Running and waiting for errors! Not seen any in running all day.
Doesnt solve the problem though, as of course the webpage now does not auto-update.

No crashing is certainly hopeful sign. You could then try something like this (unoptimised).

    // Send Events to the Web Server with the Sensor Readings
    events.send("ping", NULL, millis());

    //events.send(String(myDate).c_str(), "time", millis());

    static char myDateBuf[ 9 ] ; // make it big enough including trailing /0. Must be static if locally defined.
    myDate.toCharArray( myDateBuf, 9 ) ;  // myDate is already a String isn't it ?
    events.send( myDateBuf , "time", millis());


    //events.send(String(dTotalkWh).c_str(), "dtotal", millis());
    //events.send(String(yTotalkWh).c_str(), "ytotal", millis());
    //events.send(String(pWatts).c_str(), "pwatts", millis());
    //events.send(String(mWatts).c_str(), "mwatts", millis());
    //events.send(String(cWatts).c_str(), "cwatts", millis());
    events.send( &testBuff[ 0 ], "cwatts", millis());

@6v6gt - I really thought it was solved! At least I can understand this approach while the .cstr buisiness made no sense to me at all. However ..

   // Send Events to the Web Server with the Sensor Readings
    events.send("ping", NULL, millis());
    static char myDateBuf[ 20 ] ; // make it big enough including trailing /0. Must be static if locally defined.
    myDate.toCharArray( myDateBuf, 20 ) ;  // myDate is already a String isn't it ?
    events.send( myDateBuf , "time", millis());
    
    static char mydTotalkWh[ 10] ; // make it big enough including trailing /0. Must be static if locally defined.
    dtostrf(dTotalkWh,  7, 2, mydTotalkWh );
    events.send( mydTotalkWh , "dtotal", millis());

    static char myyTotalkWh[ 10] ; // make it big enough including trailing /0. Must be static if locally defined.
    dtostrf(yTotalkWh,  7, 2, myyTotalkWh );
    events.send( myyTotalkWh , "ytotal", millis());

    static char mypWatts[ 10] ; // make it big enough including trailing /0. Must be static if locally defined.
    itoa(pWatts, mypWatts, 7);
    events.send( mypWatts , "pwatts", millis());

    static char mymWatts[ 10] ; // make it big enough including trailing /0. Must be static if locally defined.
    itoa(mWatts, mymWatts, 7);
    line 151: events.send( mymWatts , "mwatts", millis());

    static char mycWatts[ 10] ; // make it big enough including trailing /0. Must be static if locally defined.
    itoa(cWatts, mycWatts, 7);
    events.send( mycWatts , "cwatts", millis());
    

Decoding 7 results* 0x400d7e7c: AsyncEventSourceClient::_runQueue() at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858 0x400d7f17: AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage)* at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858 0x400d7f37: AsyncEventSourceClient::write(char const, unsigned int)* at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858 0x400d7f8d: AsyncEventSource::send(char const, char const, unsigned int, unsigned int)** at c:\arduinoideportable\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-97-gc752ad5-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/functional line 1858 0x400d17d3: loop() at C:\ArduinoIDEPortable\portable\sketchbook\ESP32\SolarLoggerJune12/SolarLoggerJune12.ino line 151 0x400df329: loopTask(void)* at C:\ArduinoIDEPortable\portable\packages\esp32\hardware\esp32\1.0.6\cores\esp32/main.cpp line 23 0x40089afa: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line *355 (discriminator 1)

Which source line is this pointing to ?

Sorry @6v6GT its shown in the code above but i failed to highlight it.

 line 151: events.send( mymWatts , "mwatts", millis());