Skip to content

Latest commit

 

History

History
146 lines (94 loc) · 13.6 KB

Logging.md

File metadata and controls

146 lines (94 loc) · 13.6 KB

Message Logging

HomeSpan includes a variety of message logs with different levels of verbosity, as well built-in methods to create your own log messages and web logs.

HomeSpan Log Messages

HomeSpan log messages are typically output directly to the Arduino Serial Monitor with three possible levels of verbosity:

Log Level Output
Level 0 HomeSpan configuration data and some basic status information
Level 1 Eveything in Level 0 plus additional and more verbose status messages
Level 2 Everything im Level 1 plus all HAP communication packages sent to and from the HomeSpan device

You can set the Log Level in your sketch using the method homeSpan.setLogLevel(uint8_t level) as described in the HomeSpan API Reference. Level 0 messages are always output; Level 1 messages are only output if the Log Level is set to 1 or greater; and Level 2 messages are only output if the Log Level is set to to 2. The Log Level can also be changed dynamically via the Serial Monitor at any time by typing either the 'L0', 'L1', or 'L2' as described in the HomeSpan CLI.

You can also completely suppress all Log messages generated by HomeSpan (as well as all user-defined Log messages - see below) by setting the Log Level to -1, either by typing 'L-1' into the HomeSpan CLI or by calling homeSpan.setLogLevel(-1) in your sketch. Disabling all Log messages from being output to the Serial Monitor may be useful in cases where a separate Serial peripheral is being controlled by the ESP32. In such cases you may want to implement a physical switch on your device that automatically sets the Log Level to 0 or -1 so you don't have to recompile your sketch every time you want to enable/disable HomeSpan Log Messages.

Note that the Log Level setting has no impact on messages output by any Serial.print() or Serial.printf() statements used in a sketch. To ensure you can control such messages via the Log Level setting, use the LOG() macros below. Also note that the Log Level setting has no impact on any ESP32 diagnostic messages produced by the ESP32 operating system itself. These messages are controlled according to the Core Debug Level specified at compile time under the Tools menu of the Arduino IDE.

User-Defined Log Messages

You can add your own log messages to any sketch using HomeSpan's LOG0(), LOG1(), and LOG2() macros. Messages created with these macros will be output to the Arduino Serial Monitor according the Log Level setting described above. Each LOGn() macro (where n=[0,2]) is available in two flavors depending on the number of arguments specified:

  • LOGn(val) - when only one argument is specified, HomeSpan outputs val using the standard Arduino Serial.print(val) method, which means val can be nearly any timvariable type. The downside is you have no control over the format. For example, int n=255; LOG1(n); outputs the number "255" to the Arduino Serial Monitor, provided that the Log Level is set to 1 or greater.

  • LOGn(const char *fmt, ...) - when more than one argument is specified, HomeSpan outputs the message using the ESP32 Serial.printf(fmt, ...) method, which allows you to format messages with a variable number of arguments using standard C++ printf conventions. For example, int n=255; LOG2("The value is 0x%X",n); outputs the message "The value is 0xFF" to the Arduino Serial Monitor, provided that the Log Level is set to 2.

See Example 9 - MessageLogging for a tutorial sketch demonstrating these macros.

Web Logging

In addition to logging messages to the Arduino Serial Monitor, HomeSpan can optionally serve a Web Log page at any page address you choose. Since the Web Log is hosted as part of HomeSpan's HAP Server, its base address and port will be the same as that of your device. For example, if your device name is http://homespan-4e8eb8504e59.local (assuming port 80) and you choose "myLog" as the Web Log page address, it will be hosted at http://homespan-4e8eb8504e59.local/myLog.

Also embedded in the HomeSpan's Web Log functionality is the ability to call an NTP time server to set the device clock. This optional feature allows HomeSpan to create clock-based timestamps (e.g. Sat Apr 16 19:48:41 2022).

The HomeSpan Web Log page itself comprises two parts:

  • the top of the page provides HomeSpan-generated status information, such as the name of the device, total uptime since last reboot, and version numbers of the various software components

  • the bottom of the page posts messages you create using the WEBLOG() macro. This macro comes only in the printf-style form WEBLOG(const char *fmt, ...), similar to the second version of the LOG() macros described above.

Messages produced with WEBLOG() are also echoed to the Arduino Serial Monitor with the same priority as LOG1() messages, meaning they will be output to the Serial Monitor if the Log Level is set to 1 or greater. The Web Log page displays messages in reverse-chronological order, supplemented with the following additional items:

  • Entry Number - HomeSpan numbers each message, starting with 1 for the first message after rebooting
  • Up Time - relative message time, in the form DDD:HH:MM:SS, starting at 000:00:00:00 after rebooting
  • Log Time - absolute message time, in standard UNIX format, provided that Web Logging has been enabled with an NTP Time Server (see below)
  • Client - the IP Address of the Client connected to HomeSpan at the time the WEBLOG() message was created. Only applicable for messages produced within the update() method of a Service. Client is otherwise set to '0.0.0.0' in all other instances
  • Message - the text of the formatted message. For example, int ledNumber=5; WEBLOG("Request to turn LED %d OFF\n",ledNumber); would produce the message "Request to turn LED 5 OFF"

To enable Web Logging (it's turned off by default), call the method homeSpan.enableWebLog(), as more fully described in the HomeSpan API Reference, near the top of your sketch. This method allows you to set:

  • the total number of WEBLOG() messages to be stored - older messages are discarded in favor of newer ones once the limit you set is reached
  • the URL of an NTP time server - this is optional and only needed if you want to set the clock of the device at start-up
  • the time zone for the device - this is only needed if an NTP time server has been specified
  • the URL of the Web Log page - if unspecified, HomeSpan will serve the Web Log at a page named "status". If set to NULL, HomeSpan will process Web Log data but will not serve any Web Log pages to any HTTP requests. However, Web Log data in the form of a finished HTML page can still be accessed by the user by calling homeSpan.getWebLog() as described further below

Additional notes:

  • it is okay to include WEBLOG() messages in your sketch even if Web Logging is not enabled. In such cases HomeSpan will not serve a Web Log page, but WEBLOG() messages will still be output to the Arduino Serial Monitor if the Log Level is set to 1 or greater
  • messages are not stored in NVS and are thus not saved between reboots

See Example 19 - WebLog for a tutorial sketch demonstrating the use of homeSpan.enableWebLog() and the WEBLOG() macro.

Custom Style Sheets (CSS)

HomeSpan's Web Log normally consists of black text on a light blue background. However, you can set a Custom Style Sheet (CSS) to change the format by calling homeSpan.setWebLogCSS(const char *css), where css is constructed using HTML classes containing one or more custom style elements. HomeSpan implements the following three class names for the different parts of the Web Log:

  • bod1 - this class specifies style elements for the main body of the Web Log page, including the background color and the header text at the top (which itself is formatted as <h2>)
  • tab1 - this class specifies style elements for the status table at the top of the Web Log page
  • tab2 - this class specifies style elements for the log entry table at the botom of the Web Log page

For example, the following CSS changes the background color of the Web Log page to light yellow, the color of the header text to blue, the color of the cells in the top table to light green, and the color of the cells in the botom table to light blue. It also changes the color of the text in the header row (<th>) of the second table to red, the color of the data rows (<td>) in the second table to dark blue, and the alignment of the text in the data rows to be centered within each table cell:

homeSpan.setWebLogCSS(".bod1 {background-color:lightyellow;}"
                      ".bod1 h2 {color:blue;}"
                      ".tab1 {background-color:lightgreen;}"
                      ".tab2 {background-color:lightblue;} .tab2 th {color:red;} .tab2 td {color:darkblue; text-align:center;}"
                      );

Note that HomeSpan outputs the full content of the Web Log HTML, including whatever CSS you may have specified above, to the Serial Monitor whenever the Log Level is set to 1 or greater. Reviewing this output can be helpful when creating your own CSS.

Adding User-Defined Data and/or Custom HTML

Homespan provides a hook into the text used to generate the Web Log that you can extend to add your own data to the initial table as well as more generally add any custom HTML.

To access this text, set a Web Log callback using homeSpan.setWebLogCallback(void (*func)(String &htmlText)) where

  • func is a function of type void that takes a single argument of type String, and
  • htmlText will be set by HomeSpan to a String reference containing all the HTML text that the Web Log has already generated to produce the initial table.

To add your own data to the table, simply extend the String htmlText by adding as many <tr> and <td> HTML tags as needed. If you wish to end the table and add any other HTML, simple include the </table> tag in htmlText, and then add any other custom HTML. For example, the following function could be used to extend the initial Web Log table to show free DRAM, end the table, and provide a hot link to the HomeSpan Repo:

void extraData(String &r){
  r+="<tr><td>Free DRAM:</td><td>" + String(esp_get_free_internal_heap_size()) + " bytes</td></tr>\n"; 
  r+="</table><p><a href=\"https://github.com/HomeSpan/HomeSpan\">Click Here to Access HomeSpan Repo</a></p>";
}

To embed this custom HTML text in the Web Log, call homeSpan.setWebLogCallback(extraData) in your sketch.

Accessing Web Log HTML from within your sketch

In addition to (or as an alternative to) having HomeSpan serve HTML Web Log pages in response to HTTP requests, users can directly access the HTML text for a Web Log page from within their sketch for customized processing and handling. Since the HTML for a Web Log page can be very large, HomeSpan only generates the HTML for a Web Log page when the page has been requested, and streams the HTML in sequential chunks of 1024 bytes in response to a Web Log HTTP request. It is therefore not possible for HomeSpan to simply provide the user with a char * pointer to the HTML text for a complete Web Log. Instead, HomeSpan provides the user with the following homeSpan method to trigger the production of a Web Log page and access the resulting HTML text whenever needed:

getWebLog(void (*f)(const char *htmlText, void *data), void *userData)

  • f() - a user-defined function that returns void and takes two arguments:
    • htmlText - a null-terminated const char * pointer to a chunk of HTML text (max 1024 bytes) provided by HomeSpan
    • data - a void * pointer to any user-provided data, userData
  • userData - a void * pointer to any optional user-provided data that is passed to f() as its second argument, data

When the above method is called from a sketch, HomeSpan will repeatedly call the user-defined function f() and provide sequential chunks of HTML text for the Web Log page as the first argument, htmlText. Once all HTML chunks have been sent to the function f(), HomeSpan calls f() one final time with htmlText set to NULL to indicate there are no more HTML chunks to be sent.

The primary purpose of this function is for the user to provide their own method of serving an HTML Web Log page, such as through a secure HTTPS channel. Note this channel can be in addition to, or instead of, HomeSpan's normal serving of Web Log pages through HTTP requests depending on whether or not the URL argument used in the homeSpan.enableWebLog() method was set to NULL (disabling HomeSpan from serving Web Log pages in response to HTTP requests).

The following psuedo-code snippet shows how getWebLog() can be used:

...
homeSpan.enableWebLog(50,"pool.ntp.org","UTC",NULL);      // this enables the Web Log for 50 entries and sets the clock, but prevents HomeSpan from responding to any HTTP requests for a Web Log page
...
IF WEBLOG NEEDED THEN{
  homeSpan.getWebLog(myWebLogHandler,NULL);               // this triggers HomeSpan to produce the HTML text for a Web Log page and stream the data to myWebLogHandler without any extra user data
}
...
void myWebLogHandler(const char *htmlText, void *args){   // this is the user-defined Web Log handler (note the optional *arg parameter is not used in this example)
  if(htmlText!=NULL){
    DO SOMETHING WITH htmlText (e.g. transmit it to the user via an HTTPS connection)
  }
  else
    PERFORM ANY CLEAN-UP PROCESSING (e.g. close the HTTPS connection)
  }
}

↩️ Back to the Welcome page