|
1 | 1 | # SPIFFSLogger |
2 | 2 | A minimal library for binary data logging in ESP8266 systems. |
3 | 3 |
|
4 | | -Makes it easy to read, write and keep logs of relevant data, such as sensor readings in an efficient way, |
5 | | -by storing data in raw, binary format along with a time_t. Depending on the data, this should offer about |
6 | | -50% space savings vs. saving the same data in CSV. Daily log file rotation is performed automatically. |
| 4 | +## Features |
7 | 5 |
|
8 | | -See the [example](examples/Basic/Basic.ino) and documentation below. |
| 6 | +* Easy to use |
| 7 | +* Stores data in binary along with a UTC timestamp |
| 8 | +* Results in about 50% space spavings when compared to logging the same data in CSV |
| 9 | +* Splits data into daily files, allowing for efficient search |
| 10 | +* Automatically rotates files, deleting the ones that exceed the specified age |
| 11 | +* Uses built-in ESP/newlib time functions |
9 | 12 |
|
10 | 13 | ## Installing |
11 | | -Clone the library into your libraries folder, or download the zip and extract it manually. |
12 | 14 |
|
13 | | -## Documentation |
| 15 | +1. Download the [latest release](https://github.com/bitmario/SPIFFSLogger/releases/latest) |
| 16 | +2. Extract it into your libraries folder |
| 17 | +3. Rename the folder from `SPIFFSLogger-x.x.x` to `SPIFFSLogger` |
14 | 18 |
|
15 | | - Members | Descriptions |
16 | | ---------------------------------|--------------------------------------------- |
17 | | -`class `[`SPIFFSLogger`](#class_s_p_i_f_f_s_logger) | Minimal class template for binary data logging in ESP8266 SPIFFS. |
18 | | -`struct `[`SPIFFSLogData`](#struct_s_p_i_f_f_s_log_data) | Represents a data element as stored in SPIFFS, along with the creation timestamp. |
| 19 | +## Getting started |
19 | 20 |
|
20 | | -## class `SPIFFSLogger<T>` |
| 21 | +See the summary below and try the [example](examples/Basic/Basic.ino). You may also want to take a peek at our [documentation](extras/docs/api.md). |
21 | 22 |
|
22 | | -``` |
23 | | -class SPIFFSLogger |
24 | | - : public SPIFFSLoggerBase |
25 | | -``` |
26 | | - |
27 | | -Minimal class template for binary data logging in ESP8266 SPIFFS. |
28 | | - |
29 | | -Makes it easy to read, write and keep logs of relevant data, such as sensor readings in an efficient way, by storing data in raw, binary format along with a time_t. One file is created per UTC day to store the respective data, and deleted once it has reached the defined maximum age. |
30 | | - |
31 | | -#### Parameters |
32 | | -* `T` type to store, e.g. a struct. |
33 | | - |
34 | | -### Summary |
35 | | - |
36 | | - Members | Descriptions |
37 | | ---------------------------------|--------------------------------------------- |
38 | | -`public `[`SPIFFSLogger`](#class_s_p_i_f_f_s_logger_1afa8152a5d5d29fedbb04265cb4589359)`(const char * directory,uint16_t daysToKeep,uint16_t processInterval)` | Default constructor for [SPIFFSLogger](#class_s_p_i_f_f_s_logger). |
39 | | -`public size_t `[`write`](#class_s_p_i_f_f_s_logger_1a2e914dd1884de9900288564a41bc55a4)`(const T & value)` | Write the specified value to the end of the current log file, with the current timestamp. |
40 | | -`public size_t `[`readRows`](#class_s_p_i_f_f_s_logger_1aeceb2db3a41feb387e874f247657e19c)`(`[`SPIFFSLogData`](#struct_s_p_i_f_f_s_log_data)`< T > * output,time_t date,size_t startIdx,size_t maxCount)` | Read data from a daily logfile into a buffer. |
41 | | -`public size_t `[`readRowsBetween`](#class_s_p_i_f_f_s_logger_1a8d82d01f694528becba720e0612dc48d)`(`[`SPIFFSLogData`](#struct_s_p_i_f_f_s_log_data)`< T > * output,time_t fromTime,time_t toTime,size_t startIdx,size_t maxCount)` | |
42 | | -`public size_t `[`rowCount`](#class_s_p_i_f_f_s_logger_1ac539407d1bfebe9443393ea2e4047e29)`(time_t date)` | Get the number of entries for the specified date. |
43 | | -`public void `[`init`](#class_s_p_i_f_f_s_logger_base_1ad2270960852a999b0340fa4eab50f063)`()` | Initialize the logger. |
44 | | -`public void `[`process`](#class_s_p_i_f_f_s_logger_base_1a22fdd2b540717853ae403edbc0ed1b7f)`()` | Process the file rotation and other required operations according to the defined processInterval. |
45 | | -`protected time_t `[`_today`](#class_s_p_i_f_f_s_logger_base_1a77a967ae68a680dea5a647200ba49815) | current date, set in the last processing run |
46 | | -`protected unsigned long `[`_lastProcess`](#class_s_p_i_f_f_s_logger_base_1ac1b33a4c97b2a45b2b178a261ebbb12c) | last processing millis() |
47 | | -`protected const uint16_t `[`_processInterval`](#class_s_p_i_f_f_s_logger_base_1a517fa4d3854283ba7b2dba9bf0d09c84) | ms between processing runs |
48 | | -`protected const uint16_t `[`_daysToKeep`](#class_s_p_i_f_f_s_logger_base_1a8feb62f012879aca79d600cf217c2098) | number of days to keep logs for |
49 | | -`protected bool `[`_processNow`](#class_s_p_i_f_f_s_logger_base_1a978f0a636ce4d7a7f1640df124cc25ff) | force processing now, even if the processing interval hasn't passed |
50 | | -`protected char `[`_directory`](#class_s_p_i_f_f_s_logger_base_1a829da5d8bf3d83ed24e608bb60fc623c) | base directory for log files |
51 | | -`protected char `[`_curPath`](#class_s_p_i_f_f_s_logger_base_1a7f79553c53c7b5b6c87aaaa104d5a1e3) | path for today's file |
52 | | -`protected void `[`_pathFromDate`](#class_s_p_i_f_f_s_logger_base_1abfba26125f8b32b4c8e2e3d29d65b31f)`(char * output,time_t date)` | Converts a time_t to that day's file path. |
53 | | -`protected void `[`_updateCurPath`](#class_s_p_i_f_f_s_logger_base_1aa5679e47e144e591b5fa90fb31b65cbd)`()` | Updates the current path to match today's date. |
54 | | -`protected void `[`_runRotation`](#class_s_p_i_f_f_s_logger_base_1a2e9e45428e1ffbe989dd7679c5def4fe)`()` | Deletes files older than the defined age limit. |
55 | | - |
56 | | -### Members |
57 | | - |
58 | | -#### `public `[`SPIFFSLogger`](#class_s_p_i_f_f_s_logger_1afa8152a5d5d29fedbb04265cb4589359)`(const char * directory,uint16_t daysToKeep,uint16_t processInterval)` |
59 | | - |
60 | | -Default constructor for [SPIFFSLogger](#class_s_p_i_f_f_s_logger). |
61 | | - |
62 | | -#### Parameters |
63 | | -* `directory` char array with the base directory where files will be stored. Should not include trailing slash and should be 20 characters or less. |
64 | | - |
65 | | -* `daysToKeep` number of days to keep in flash. Once files are past this age, they are deleted. |
66 | | - |
67 | | -* `processInterval` milliseconds between file directory updates and file rotation. |
68 | | - |
69 | | -#### `public size_t `[`write`](#class_s_p_i_f_f_s_logger_1a2e914dd1884de9900288564a41bc55a4)`(const T & value)` |
70 | | - |
71 | | -Write the specified value to the end of the current log file, with the current timestamp. |
72 | | - |
73 | | -#### Parameters |
74 | | -* `value` the value to write |
75 | | - |
76 | | -#### `public size_t `[`readRows`](#class_s_p_i_f_f_s_logger_1aeceb2db3a41feb387e874f247657e19c)`(`[`SPIFFSLogData`](#struct_s_p_i_f_f_s_log_data)`< T > * output,time_t date,size_t startIdx,size_t maxCount)` |
77 | | - |
78 | | -Read data from a daily logfile into a buffer. |
79 | | - |
80 | | -#### Parameters |
81 | | -* `output` buffer where data will be written |
82 | | - |
83 | | -* `date` time_t representing the date of the file |
84 | | - |
85 | | -* `startIdx` 0-based index of the entries to read (row number) |
86 | | - |
87 | | -* `maxCount` maximum number of entries to read |
88 | | - |
89 | | -#### Returns |
90 | | -number of entries read |
91 | | - |
92 | | -#### `public size_t `[`readRowsBetween`](#class_s_p_i_f_f_s_logger_1a8d82d01f694528becba720e0612dc48d)`(`[`SPIFFSLogData`](#struct_s_p_i_f_f_s_log_data)`< T > * output,time_t fromTime,time_t toTime,size_t startIdx,size_t maxCount)` |
93 | | - |
94 | | -#### `public size_t `[`rowCount`](#class_s_p_i_f_f_s_logger_1ac539407d1bfebe9443393ea2e4047e29)`(time_t date)` |
| 23 | +### Required includes |
95 | 24 |
|
96 | | -Get the number of entries for the specified date. |
97 | | - |
98 | | -#### Parameters |
99 | | -* `date` a time_t representing the day to check |
100 | | - |
101 | | -#### Returns |
102 | | -number of entries |
103 | | - |
104 | | -#### `public void `[`init`](#class_s_p_i_f_f_s_logger_base_1ad2270960852a999b0340fa4eab50f063)`()` |
105 | | - |
106 | | -Initialize the logger. |
107 | | - |
108 | | -Should be called after initializing SPIFFS and before before any other method. |
109 | | - |
110 | | -#### `public void `[`process`](#class_s_p_i_f_f_s_logger_base_1a22fdd2b540717853ae403edbc0ed1b7f)`()` |
111 | | - |
112 | | -Process the file rotation and other required operations according to the defined processInterval. |
113 | | - |
114 | | -Should be called as often as possible, i.e. in loop(). |
115 | | - |
116 | | -#### `protected time_t `[`_today`](#class_s_p_i_f_f_s_logger_base_1a77a967ae68a680dea5a647200ba49815) |
117 | | - |
118 | | -current date, set in the last processing run |
119 | | - |
120 | | -#### `protected unsigned long `[`_lastProcess`](#class_s_p_i_f_f_s_logger_base_1ac1b33a4c97b2a45b2b178a261ebbb12c) |
121 | | - |
122 | | -last processing millis() |
123 | | - |
124 | | -#### `protected const uint16_t `[`_processInterval`](#class_s_p_i_f_f_s_logger_base_1a517fa4d3854283ba7b2dba9bf0d09c84) |
| 25 | +```cpp |
| 26 | +#include <SPIFFSLogger.h> |
| 27 | +``` |
125 | 28 |
|
126 | | -ms between processing runs |
| 29 | +### The SPIFFSLogData<T\> struct |
127 | 30 |
|
128 | | -#### `protected const uint16_t `[`_daysToKeep`](#class_s_p_i_f_f_s_logger_base_1a8feb62f012879aca79d600cf217c2098) |
| 31 | +This struct represents the data as stored in SPIFFS (including the timestamp). It is returned in any logger read operations. |
129 | 32 |
|
130 | | -number of days to keep logs for |
| 33 | +Definition: |
131 | 34 |
|
132 | | -#### `protected bool `[`_processNow`](#class_s_p_i_f_f_s_logger_base_1a978f0a636ce4d7a7f1640df124cc25ff) |
| 35 | +```cpp |
| 36 | +template <class T> |
| 37 | +struct SPIFFSLogData |
| 38 | +{ |
| 39 | + time_t timestampUTC; /** creation time in UTC */ |
| 40 | + T data; /** data of type T */ |
| 41 | +}; |
| 42 | +``` |
133 | 43 |
|
134 | | -force processing now, even if the processing interval hasn't passed |
| 44 | +### The SPIFFSLogger<T\> class |
135 | 45 |
|
136 | | -#### `protected char `[`_directory`](#class_s_p_i_f_f_s_logger_base_1a829da5d8bf3d83ed24e608bb60fc623c) |
| 46 | +This is the core of the library. You can create your logger like so: |
137 | 47 |
|
138 | | -base directory for log files |
| 48 | +```cpp |
| 49 | +// store ints, saving files in /log/ and keeping today + 7 days of history |
| 50 | +SPIFFSLogger<int> logger("/log", 7); |
| 51 | +``` |
139 | 52 |
|
140 | | -#### `protected char `[`_curPath`](#class_s_p_i_f_f_s_logger_base_1a7f79553c53c7b5b6c87aaaa104d5a1e3) |
| 53 | +We can also store a struct (which is probably more useful!): |
141 | 54 |
|
142 | | -path for today's file |
| 55 | +```cpp |
| 56 | +struct EnvData { |
| 57 | + float temperature; |
| 58 | + float humidity; |
| 59 | + uint16_t pressure; |
| 60 | +}; |
143 | 61 |
|
144 | | -#### `protected void `[`_pathFromDate`](#class_s_p_i_f_f_s_logger_base_1abfba26125f8b32b4c8e2e3d29d65b31f)`(char * output,time_t date)` |
| 62 | +SPIFFSLogger<EnvData> logger("/log", 7); |
| 63 | +``` |
145 | 64 |
|
146 | | -Converts a time_t to that day's file path. |
| 65 | +#### Initializing the logger |
147 | 66 |
|
148 | | -#### `protected void `[`_updateCurPath`](#class_s_p_i_f_f_s_logger_base_1aa5679e47e144e591b5fa90fb31b65cbd)`()` |
| 67 | +This library uses the ESP8266 SPIFFS and built-in time functions so you must initialize those components and then call `logger.init()`. |
149 | 68 |
|
150 | | -Updates the current path to match today's date. |
| 69 | +Your `setup()` should look something like this: |
151 | 70 |
|
152 | | -#### `protected void `[`_runRotation`](#class_s_p_i_f_f_s_logger_base_1a2e9e45428e1ffbe989dd7679c5def4fe)`()` |
| 71 | +```cpp |
| 72 | +void setup() { |
| 73 | + // configure time however you like, we use NTP here |
| 74 | + wifiSetup(); // ommitted for brevity |
| 75 | + configTime(0, 0, "pool.ntp.org"); |
| 76 | + |
| 77 | + // initialize SPIFFS |
| 78 | + SPIFFS.begin(); |
| 79 | + |
| 80 | + // initialize our logger |
| 81 | + logger.init(); |
| 82 | +} |
| 83 | +``` |
153 | 84 |
|
154 | | -Deletes files older than the defined age limit. |
| 85 | +#### Writing data |
155 | 86 |
|
156 | | -## struct `SPIFFSLogData<T>` |
| 87 | +Simply call `logger.write()` and the data will be logged with the current timestamp: |
157 | 88 |
|
158 | | -Represents a data element as stored in SPIFFS, along with the creation timestamp. |
| 89 | +```cpp |
| 90 | +struct EnvData data = { 23.54, 50.67, 1020 }; |
| 91 | +logger.write(data); |
| 92 | +``` |
159 | 93 |
|
160 | | -#### Parameters |
161 | | -* `T` type to store, e.g. a struct. |
| 94 | +#### Reading data |
162 | 95 |
|
163 | | -### Summary |
| 96 | +Reading the first row of today's logfile: |
164 | 97 |
|
165 | | - Members | Descriptions |
166 | | ---------------------------------|--------------------------------------------- |
167 | | -`public time_t `[`timestampUTC`](#struct_s_p_i_f_f_s_log_data_1a692b3adc90780d9388d6833d2170400c) | creation time in UTC |
168 | | -`public T `[`data`](#struct_s_p_i_f_f_s_log_data_1a071121efdc7f6d95adc4dcdf736a84ec) | data of type T |
| 98 | +```cpp |
| 99 | +SPIFFSLogData<EnvData> data; |
| 100 | +logger.readRows(&data, time(nullptr), 0, 1); |
| 101 | +Serial.printf("TS: %d, T: %.2f, H: %.2f, %u\n", |
| 102 | + data.timestampUTC, |
| 103 | + data.data.temperature, |
| 104 | + data.data.humidity, |
| 105 | + data.data.pressure); |
| 106 | +``` |
169 | 107 |
|
170 | | -### Members |
| 108 | +Or the last row: |
171 | 109 |
|
172 | | -#### `public time_t `[`timestampUTC`](#struct_s_p_i_f_f_s_log_data_1a692b3adc90780d9388d6833d2170400c) |
| 110 | +```cpp |
| 111 | +const size_t rowCount = logger.rowCount(now); |
| 112 | +logger.readRows(&data, now, rowCount - 1, 1); |
| 113 | +``` |
173 | 114 |
|
174 | | -creation time in UTC |
| 115 | +Or 25 rows starting at the 50th: |
175 | 116 |
|
176 | | -#### `public T `[`data`](#struct_s_p_i_f_f_s_log_data_1a071121efdc7f6d95adc4dcdf736a84ec) |
| 117 | +```cpp |
| 118 | +SPIFFSLogData<EnvData> data[25]; |
| 119 | +logger.readRows(data, time(nullptr), 49, 25); |
| 120 | +``` |
177 | 121 |
|
178 | | -data of type T |
| 122 | +#### Filtering data |
| 123 | + |
| 124 | +Retrieving data from the last 20 minutes: |
| 125 | + |
| 126 | +```cpp |
| 127 | +SPIFFSLogData<EnvData> data[25]; |
| 128 | +size_t count = logger.readRowsBetween(&data, // output |
| 129 | + now - (60 * 20), // time start (inclusive) |
| 130 | + now, // time end (inclusive) |
| 131 | + 0, // start index within results |
| 132 | + 25 // max number of rows to fetch (size your output buffer accordingly!) |
| 133 | +); |
| 134 | + |
| 135 | +for (int i=0; i<count; i++) { |
| 136 | + Serial.printf("TS: %d, T: %.2f, H: %.2f, %u\n", |
| 137 | + data[i].timestampUTC, |
| 138 | + data[i].data.temperature, |
| 139 | + data[i].data.humidity, |
| 140 | + data[i].data.pressure); |
| 141 | +} |
| 142 | +``` |
179 | 143 |
|
180 | 144 | ## License |
181 | 145 | Licensed under the GNU LGPLv3, see the [LICENSE](LICENSE) file. |
0 commit comments