Skip to content

Commit e902e08

Browse files
committed
feat: options refactor and http timeout
1 parent 2c8ad4c commit e902e08

File tree

12 files changed

+600
-257
lines changed

12 files changed

+600
-257
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
## Version 3.4.0 (in progres)
33
### Features
44
- [#89](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/89) - ESP8266 only - Added Max Fragment Length Negotiation for TLS communicaton to reduce memory allocation. If server supports MFLN, it saves ~15kB. Standalone InfluxDB OSS server doesn't support MFLN, Cloud yes. To leverage MFLN for standalone OSS, a reverse proxy needs to be used.
5+
- [#91](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/91) - Improved API for settings of write and HTTP options:
6+
- Introduced `WriteOptions` to wrap the write related options (write precision, batch-size, etc). It offers fluent style API allowing to change only the required options. `InfluxDBClient` has overloaded `setWriteOptions(const WriteOptions& writeOptions)` method.
7+
- Introduced `HTTPOptions` to wrap the HTTP related options (e.g. reusing connection). It offers fluent style API allowing to change only the required options. `InfluxDBClient` has `setHTTPOptions(const HTTPOptions& httpOptions)` method.
8+
- Added possibility to set HTTP response read timeout (part of the `HTTPOptions`).
9+
- Method `InfluxDBClient::void setWriteOptions(WritePrecision precision, uint16_t batchSize = 1, uint16_t bufferSize = 5, uint16_t flushInterval = 60, bool preserveConnection = true)` is deprecated and it will be removed in the next release.
510

611
### Documentation
712
- [#87](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/87) - Fixed include file name in the Readme

README.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ If points have no timestamp assigned, InfluxDB assigns timestamp at the time of
155155
156156
InfuxDB allows sending timestamp in various precisions - nanoseconds, microseconds, milliseconds or seconds. The milliseconds precision is usually enough for using on Arduino. Maximum avavailable precision is microseconds. Setting to nanosecond will just add zeroes for microseconds fraction.
157157
158-
The client has to be configured with time precision. The default settings is not using the timestamp. The `setWriteOptions` functions allow setting various parameters and one of them is __write precision__:
158+
The client has to be configured with a time precision. The default settings is not using the timestamp, which means server will assign timestamp. The `setWriteOptions` functions allow setting custom `WriteOptions` params and one of them is __write precision__:
159159
``` cpp
160160
// Set write precision to milliseconds. Leave other parameters default.
161-
client.setWriteOptions(WritePrecision::MS);
161+
client.setWriteOptions(WriteOptions().writePrecision(WritePrecision::MS));
162162
```
163163
When a write precision is configured, the client will automatically assign current time to the timestamp of each written point, which doesn't have a timestamp assigned.
164164

@@ -220,21 +220,22 @@ For example, if you would like to see updates (on the dashboard or in processing
220220

221221
In case that data should be written in longer periods and gathered data consists of several points batch size should be set to an expected number of points.
222222

223-
To set batch size we use [setWriteOptions](#write-options) function, where second parameter controls batch size:
223+
To set batch size we use `WriteOptions` object and [setWriteOptions](#write-options) function:
224224
```cpp
225225
// Enable messages batching
226-
client.setWriteOptions(WritePrecision::MS, 10);
226+
client.setWriteOptions(WriteOptions().batchSize(10));
227227
```
228228
Writing point will add a point to the underlying buffer until the batch size is reached:
229229
```cpp
230230
// Write first point to the buffer
231+
// Buffered write always returns `true`
231232
client.writePoint(point1);
232233
// Write second point to the buffer
233234
client.writePoint(point2);
234235
..
235-
// Write nineth point to the buffer, returns
236+
// Write nineth point to the buffer
236237
client.writePoint(point9);
237-
// Writing tenth point will cause flushing buffer
238+
// Writing tenth point will cause flushing buffer and returns actual write result.
238239
if(!client.writePoint(point10)) {
239240
Serial.print("InfluxDB write failed: ");
240241
Serial.println(client.getLastErrorMessage());
@@ -246,12 +247,12 @@ In case of a number of points is not always the same, set batch size to the maxi
246247
## Buffer Handling and Retrying
247248
InfluxDB contains an underlying buffer for handling writing in batches and automatic retrying on server backpressure and connection failure.
248249

249-
Its size is controled by the 3rd parameter of [setWriteOptions](#write-options) function:
250+
Its size is controled by the `bufferSize` param of [WriteOptions](#write-options) object:
250251
```cpp
251-
// Enable messages batching
252-
client.setWriteOptions(WritePrecision::MS, 10, 30);
252+
// Increase buffer to allow caching of failed writes
253+
client.setWriteOptions(WriteOptions().bufferSize(50));
253254
```
254-
The third parameter specifies the buffer size. The recommended size is at least 2 x batch size.
255+
The recommended size is at least 2 x batch size.
255256

256257
State of the buffer can be determined via two functions:
257258
- `isBufferEmpty()` - Returns true if buffer is empty
@@ -278,15 +279,21 @@ Other functions for dealing with buffer:
278279
Check [SecureBatchWrite example](examples/SecureBatchWrite/SecureBatchWrite.ino) for example code of buffer handling functions.
279280
280281
## Write Options
281-
Writing points can be controlled via several parameters in `setWriteOptions` function:
282+
Writing points can be controlled via `WriteOptions`, which is set in `setWriteOptions` function:
282283
283284
| Parameter | Default Value | Meaning |
284285
|-----------|---------------|---------|
285-
| precision | `WritePrecision::NoTime` | Timestamp precision of written data |
286+
| writePrecision | `WritePrecision::NoTime` | Timestamp precision of written data |
286287
| batchSize | `1` | Number of points that will be written to the database at once |
287288
| bufferSize | `5` | Maximum number of points in buffer. Buffer contains new data that will be written to the database and also data that failed to be written due to network failure or server overloading |
288289
| flushInterval | `60` | Maximum time(in seconds) data will be held in buffer before are written to the db |
289-
| preserveConnection | `false` | true if underlying HTTP connection should be kept open |
290+
291+
## HTTP Options
292+
`HTTPOptions` controls some aspects of HTTP communication and they are set via `setHTTPOptions` function:
293+
| Parameter | Default Value | Meaning |
294+
|-----------|---------------|---------|
295+
| reuseConnection | `false` | Whether HTTP connection should be kept open after inital communicaton. Usable for frequent writes/queries. |
296+
| httpReadTimeout | `5000` | Timeout (ms) for reading server response |
290297
291298
## Secure Connection
292299
Connecting to a secured server requires configuring client to trust the server. This is achieved by providing client with a server certificate, certificate authority certificate or certificate SHA1 fingerprint.

examples/SecureBatchWrite/SecureBatchWrite.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void setup() {
9393
}
9494

9595
// Enable messages batching and retry buffer
96-
client.setWriteOptions(WRITE_PRECISION, MAX_BATCH_SIZE, WRITE_BUFFER_SIZE);
96+
client.setWriteOptions(WriteOptions().writePrecision(WRITE_PRECISION).batchSize(MAX_BATCH_SIZE).bufferSize(WRITE_BUFFER_SIZE));
9797
}
9898

9999
void loop() {

src/InfluxDb.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ void Influxdb::begin() {
122122
*/
123123
void Influxdb::prepare(InfluxData data) {
124124
++_preparedPoints;
125-
if(_batchSize <= _preparedPoints) {
125+
if(_writeOptions._batchSize <= _preparedPoints) {
126126
// for preparation, batchsize must be greater than number of prepared points, or it will send data right away
127-
_batchSize = _preparedPoints+1;
128-
reserveBuffer(2*_batchSize);
127+
_writeOptions._batchSize = _preparedPoints+1;
128+
reserveBuffer(2*_writeOptions._batchSize);
129129
}
130130
write(data);
131131
}

src/InfluxDbClient.cpp

Lines changed: 41 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -68,93 +68,8 @@ static String precisionToString(WritePrecision precision, uint8_t version = 2) {
6868
}
6969
}
7070

71-
Point::Point(String measurement):
72-
_measurement(escapeKey(measurement, false)),
73-
_tags(""),
74-
_fields(""),
75-
_timestamp("")
76-
{
77-
78-
}
79-
80-
void Point::addTag(String name, String value) {
81-
if(_tags.length() > 0) {
82-
_tags += ',';
83-
}
84-
_tags += escapeKey(name);
85-
_tags += '=';
86-
_tags += escapeKey(value);
87-
}
88-
89-
void Point::addField(String name, const char *value) {
90-
putField(name, "\"" + escapeValue(value) + "\"");
91-
}
92-
93-
void Point::putField(String name, String value) {
94-
if(_fields.length() > 0) {
95-
_fields += ',';
96-
}
97-
_fields += escapeKey(name);
98-
_fields += '=';
99-
_fields += value;
100-
}
101-
102-
String Point::toLineProtocol() const {
103-
String line = _measurement;
104-
if(hasTags()) {
105-
line += "," + _tags;
106-
}
107-
if(hasFields()) {
108-
line += " " + _fields;
109-
}
110-
if(hasTime()) {
111-
line += " " + _timestamp;
112-
}
113-
return line;
114-
}
115-
116-
void Point::setTime(WritePrecision precision) {
117-
struct timeval tv;
118-
gettimeofday(&tv, NULL);
119-
120-
switch(precision) {
121-
case WritePrecision::NS:
122-
setTime(getTimeStamp(&tv,9));
123-
break;
124-
case WritePrecision::US:
125-
setTime(getTimeStamp(&tv,6));
126-
break;
127-
case WritePrecision::MS:
128-
setTime(getTimeStamp(&tv,3));
129-
break;
130-
case WritePrecision::S:
131-
setTime(getTimeStamp(&tv,0));
132-
break;
133-
case WritePrecision::NoTime:
134-
_timestamp = "";
135-
break;
136-
}
137-
}
138-
139-
void Point::setTime(unsigned long long timestamp) {
140-
_timestamp = timeStampToString(timestamp);
141-
}
142-
143-
void Point::setTime(String timestamp) {
144-
_timestamp = timestamp;
145-
}
146-
147-
void Point::clearFields() {
148-
_fields = "";
149-
_timestamp = "";
150-
}
151-
152-
void Point:: clearTags() {
153-
_tags = "";
154-
}
155-
15671
InfluxDBClient::InfluxDBClient() {
157-
_pointsBuffer = new String[_bufferSize];
72+
_pointsBuffer = new String[_writeOptions._bufferSize];
15873
}
15974

16075
InfluxDBClient::InfluxDBClient(const char *serverUrl, const char *db):InfluxDBClient() {
@@ -233,7 +148,7 @@ bool InfluxDBClient::init() {
233148
} else {
234149
_wifiClient = new WiFiClient;
235150
}
236-
_httpClient.setReuse(false);
151+
_httpClient.setReuse(_httpOptions._connectionReuse);
237152

238153
_httpClient.setUserAgent(FPSTR(UserAgent));
239154
return true;
@@ -342,66 +257,72 @@ void InfluxDBClient::setUrls() {
342257
INFLUXDB_CLIENT_DEBUG(" writeUrl: %s\n", _writeUrl.c_str());
343258
INFLUXDB_CLIENT_DEBUG(" queryUrl: %s\n", _queryUrl.c_str());
344259
}
345-
if(_writePrecision != WritePrecision::NoTime) {
260+
if(_writeOptions._writePrecision != WritePrecision::NoTime) {
346261
_writeUrl += "&precision=";
347-
_writeUrl += precisionToString(_writePrecision, _dbVersion);
262+
_writeUrl += precisionToString(_writeOptions._writePrecision, _dbVersion);
348263
INFLUXDB_CLIENT_DEBUG(" writeUrl: %s\n", _writeUrl.c_str());
349264
}
350265

351266
}
352267

353268
void InfluxDBClient::setWriteOptions(WritePrecision precision, uint16_t batchSize, uint16_t bufferSize, uint16_t flushInterval, bool preserveConnection) {
354-
if(_writePrecision != precision) {
355-
_writePrecision = precision;
269+
setWriteOptions(WriteOptions().writePrecision(precision).batchSize(batchSize).bufferSize(bufferSize).flushIntervalSec(flushInterval));
270+
setHTTPOptions(_httpOptions.connectionReuse(preserveConnection));
271+
}
272+
273+
void InfluxDBClient::setWriteOptions(const WriteOptions & writeOptions) {
274+
if(_writeOptions._writePrecision != writeOptions._writePrecision) {
275+
_writeOptions._writePrecision = writeOptions._writePrecision;
356276
setUrls();
357277
}
358-
if(batchSize > 0) {
359-
_batchSize = batchSize;
360-
}
361-
if(bufferSize < batchSize) {
362-
bufferSize = 2*batchSize;
363-
INFLUXDB_CLIENT_DEBUG("[D] Changing buffer size to %d\n", bufferSize);
278+
if(writeOptions._batchSize > 0) {
279+
_writeOptions._batchSize = writeOptions._batchSize;
364280
}
365-
if(_bufferSize > 0 && bufferSize > 0 && _bufferSize != bufferSize) {
366-
_bufferSize = bufferSize;
367-
if(_bufferSize < _batchSize) {
368-
_bufferSize = 2*_batchSize;
369-
INFLUXDB_CLIENT_DEBUG("[D] Changing buffer size to %d\n", _bufferSize);
281+
if(_writeOptions._bufferSize > 0 && writeOptions._bufferSize > 0 && _writeOptions._bufferSize != writeOptions._bufferSize) {
282+
_writeOptions._bufferSize = writeOptions._bufferSize;
283+
if(_writeOptions._bufferSize < _writeOptions._batchSize) {
284+
_writeOptions._bufferSize = 2*_writeOptions._batchSize;
285+
INFLUXDB_CLIENT_DEBUG("[D] Changing buffer size to %d\n", _writeOptions._bufferSize);
370286
}
371287
resetBuffer();
372288
}
373-
_flushInterval = flushInterval;
374-
_httpClient.setReuse(preserveConnection);
289+
_writeOptions._flushInterval = writeOptions._flushInterval;
290+
}
291+
292+
void InfluxDBClient::setHTTPOptions(const HTTPOptions & httpOptions) {
293+
_httpOptions = httpOptions;
294+
_httpClient.setReuse(_httpOptions._connectionReuse);
295+
_httpClient.setTimeout(_httpOptions._httpReadTimeout);
375296
}
376297

377298
void InfluxDBClient::resetBuffer() {
378299
if(_pointsBuffer) {
379300
delete [] _pointsBuffer;
380301
}
381-
_pointsBuffer = new String[_bufferSize];
302+
_pointsBuffer = new String[_writeOptions._bufferSize];
382303
_bufferPointer = 0;
383304
_batchPointer = 0;
384305
_bufferCeiling = 0;
385306
}
386307

387308
void InfluxDBClient::reserveBuffer(int size) {
388-
if(size > _bufferSize) {
309+
if(size > _writeOptions._bufferSize) {
389310
String *newBuffer = new String[size];
390-
INFLUXDB_CLIENT_DEBUG("Resising buffer from %d to %d\n", _bufferSize, size);
311+
INFLUXDB_CLIENT_DEBUG("Resizing buffer from %d to %d\n", _writeOptions._bufferSize, size);
391312
for(int i=0;i<_bufferCeiling; i++) {
392313
newBuffer[i] = _pointsBuffer[i];
393314
}
394315

395316
delete [] _pointsBuffer;
396317
_pointsBuffer = newBuffer;
397-
_bufferSize = size;
318+
_writeOptions._bufferSize = size;
398319
}
399320
}
400321

401322
bool InfluxDBClient::writePoint(Point & point) {
402323
if (point.hasFields()) {
403-
if(_writePrecision != WritePrecision::NoTime && !point.hasTime()) {
404-
point.setTime(_writePrecision);
324+
if(_writeOptions._writePrecision != WritePrecision::NoTime && !point.hasTime()) {
325+
point.setTime(_writeOptions._writePrecision);
405326
}
406327
String line = point.toLineProtocol();
407328
return writeRecord(line);
@@ -412,15 +333,15 @@ bool InfluxDBClient::writePoint(Point & point) {
412333
bool InfluxDBClient::writeRecord(String &record) {
413334
_pointsBuffer[_bufferPointer] = record;
414335
_bufferPointer++;
415-
if(_bufferPointer == _bufferSize) {
336+
if(_bufferPointer == _writeOptions._bufferSize) {
416337
_bufferPointer = 0;
417338
INFLUXDB_CLIENT_DEBUG("[W] Reached buffer size, old points will be overwritten\n");
418339
if(isBufferFull()) {
419340
//if already isBufferFull
420341
_batchPointer = 0;
421342
}
422343
}
423-
if(_bufferCeiling < _bufferSize) {
344+
if(_bufferCeiling < _writeOptions._bufferSize) {
424345
_bufferCeiling++;
425346
}
426347
if(isBufferFull() && _batchPointer < _bufferPointer) {
@@ -432,9 +353,9 @@ bool InfluxDBClient::writeRecord(String &record) {
432353

433354
bool InfluxDBClient::checkBuffer() {
434355
// in case we (over)reach batchSize with non full buffer
435-
bool bufferReachedBatchsize = !isBufferFull() && _bufferPointer - _batchPointer >= _batchSize;
356+
bool bufferReachedBatchsize = !isBufferFull() && _bufferPointer - _batchPointer >= _writeOptions._batchSize;
436357
// or flush interval timed out
437-
bool flushTimeout = _flushInterval > 0 && _lastFlushed > 0 && (millis()/1000 - _lastFlushed) > _flushInterval;
358+
bool flushTimeout = _writeOptions._flushInterval > 0 && _lastFlushed > 0 && (millis()/1000 - _lastFlushed) > _writeOptions._flushInterval;
438359

439360
if(bufferReachedBatchsize || flushTimeout || isBufferFull() ) {
440361
INFLUXDB_CLIENT_DEBUG("[D] Flushing buffer: is oversized %s, is timeout %s, is buffer full %s\n", bufferReachedBatchsize?"true":"false",flushTimeout?"true":"false", isBufferFull()?"true":"false");
@@ -464,9 +385,9 @@ bool InfluxDBClient::flushBuffer() {
464385
_lastFlushed = millis()/1000;
465386
_batchPointer += size;
466387
//did we got over top?
467-
if(_batchPointer >= _bufferSize) {
388+
if(_batchPointer >= _writeOptions._bufferSize) {
468389
// restart _batchPointer in ring buffer from start
469-
_batchPointer = _batchPointer - _bufferSize;
390+
_batchPointer = _batchPointer - _writeOptions._bufferSize;
470391
// we reached buffer size, that means buffer was full and now lower ceiling
471392
_bufferCeiling = _bufferPointer;
472393
}
@@ -493,7 +414,7 @@ char *InfluxDBClient::prepareBatch(int &size) {
493414
size = 0;
494415
int length = 0;
495416
char *buff = nullptr;
496-
uint16_t top = _batchPointer+_batchSize;
417+
uint16_t top = _batchPointer+_writeOptions._batchSize;
497418
INFLUXDB_CLIENT_DEBUG("[D] Prepare batch: bufferPointer: %d, batchPointer: %d, ceiling %d\n", _bufferPointer, _batchPointer, _bufferCeiling);
498419
if(top > _bufferCeiling ) {
499420
// are we returning to the begining?
@@ -510,14 +431,14 @@ char *InfluxDBClient::prepareBatch(int &size) {
510431
if(top > _batchPointer) {
511432
size = top - _batchPointer;
512433
} else if(top < _batchPointer) {
513-
size = _bufferSize - (_batchPointer - top);
434+
size = _writeOptions._bufferSize - (_batchPointer - top);
514435
}
515436
INFLUXDB_CLIENT_DEBUG("[D] Prepare batch size %d\n", size);
516437
if(size) {
517438
int i = _batchPointer;
518439
for(int c=0; c < size; c++) {
519440
length += _pointsBuffer[i++].length();
520-
if(i == _bufferSize) {
441+
if(i == _writeOptions._bufferSize) {
521442
i = 0;
522443
}
523444
yield();
@@ -530,7 +451,7 @@ char *InfluxDBClient::prepareBatch(int &size) {
530451
for(int c=0; c < size; c++) {
531452
strcat(buff+strlen(buff), _pointsBuffer[i++].c_str());
532453
strcat(buff+strlen(buff), "\n");
533-
if(i == _bufferSize) {
454+
if(i == _writeOptions._bufferSize) {
534455
i = 0;
535456
}
536457
yield();

0 commit comments

Comments
 (0)