Skip to content

Commit 6b01dc9

Browse files
authored
Merge pull request #193 from tobiasschuerg/fix/timestamp
fix: timestamp
2 parents 8f4ab57 + 9091de3 commit 6b01dc9

19 files changed

+189
-67
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# Changelog
2+
## Unreleased
3+
### Fixes
4+
- [193](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/193) - Automatically adjusting point timestamp according to the setting of write precision.
5+
26
## 3.12.0 [2022-03-21]
37
### Features
48
- [185](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/185) - Added diagnostic server connection state getter `bool InfluxDBClient::isConnected()`

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -678,10 +678,10 @@ boolean success = influx.write();
678678
## Troubleshooting
679679
All db methods return status. Value `false` means something went wrong. Call `getLastErrorMessage()` to get the error message.
680680

681-
When error message doesn't help to explain the bad behavior, go to the library sources and in the file `src/InfluxDBClient.cpp` uncomment line 32:
681+
When error message doesn't help to explain the bad behavior, go to the library sources and in the file `src/util/debug.h` uncomment line 33:
682682
```cpp
683683
// Uncomment bellow in case of a problem and rebuild sketch
684-
#define INFLUXDB_CLIENT_DEBUG
684+
#define INFLUXDB_CLIENT_DEBUG_ENABLE
685685
```
686686
Then upload your sketch again and see the debug output in the Serial Monitor.
687687

src/BucketsClient.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include "BucketsClient.h"
2828
#include "util/helpers.h"
2929

30-
//#define INFLUXDB_CLIENT_DEBUG_ENABLE
3130
#include "util/debug.h"
3231

3332
static const char *propTemplate PROGMEM = "\"%s\":";

src/HTTPService.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
#include "Platform.h"
44
#include "Version.h"
55

6-
// Uncomment bellow in case of a problem and rebuild sketch
7-
//#define INFLUXDB_CLIENT_DEBUG_ENABLE
86
#include "util/debug.h"
97

108
static const char UserAgent[] PROGMEM = "influxdb-client-arduino/" INFLUXDB_CLIENT_VERSION " (" INFLUXDB_CLIENT_PLATFORM " " INFLUXDB_CLIENT_PLATFORM_VERSION ")";

src/InfluxData.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929

3030
void InfluxData::setTimestamp(long int seconds)
3131
{
32-
_timestamp = timeStampToString(seconds) + "000000000";
32+
_timestamp = timeStampToString(seconds,9);
33+
strcat(_timestamp, "000000000");
3334
}
3435

3536
String InfluxData::toString() const {

src/InfluxDbClient.cpp

+35-5
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
#include "Platform.h"
2929
#include "Version.h"
3030

31-
// Uncomment bellow in case of a problem and rebuild sketch
32-
//#define INFLUXDB_CLIENT_DEBUG_ENABLE
3331
#include "util/debug.h"
3432

3533
static const char TooEarlyMessage[] PROGMEM = "Cannot send request yet because of applied retry strategy. Remaining ";
@@ -287,17 +285,49 @@ void InfluxDBClient::reserveBuffer(int size) {
287285
}
288286
}
289287

290-
bool InfluxDBClient::writePoint(Point & point) {
291-
if (point.hasFields()) {
292-
if(_writeOptions._writePrecision != WritePrecision::NoTime && !point.hasTime()) {
288+
void InfluxDBClient::addZerosToTimestamp(Point &point, int zeroes) {
289+
char *ts = point._timestamp, *s;
290+
point._timestamp = new char[strlen(point._timestamp) + 1 + zeroes];
291+
strcpy(point._timestamp, ts);
292+
s = point._timestamp+strlen(ts);
293+
for(int i=0;i<zeroes;i++) {
294+
*s++ = '0';
295+
}
296+
*s = 0;
297+
delete [] ts;
298+
}
299+
300+
void InfluxDBClient::checkPrecisions(Point & point) {
301+
if(_writeOptions._writePrecision != WritePrecision::NoTime) {
302+
if(!point.hasTime()) {
293303
point.setTime(_writeOptions._writePrecision);
304+
// Check different write precisions
305+
} else if(point._tsWritePrecision != WritePrecision::NoTime && point._tsWritePrecision != _writeOptions._writePrecision) {
306+
int diff = int(point._tsWritePrecision) - int(_writeOptions._writePrecision);
307+
if(diff > 0) { //point has higher precision, cut
308+
point._timestamp[strlen(point._timestamp)-diff*3] = 0;
309+
} else { //point has lower precision, add zeroes
310+
addZerosToTimestamp(point, diff*-3);
311+
}
294312
}
313+
// check someone set WritePrecision on point and not on client. NS precision is ok, cause it is default on server
314+
} else if(point.hasTime() && point._tsWritePrecision != WritePrecision::NoTime && point._tsWritePrecision != WritePrecision::NS) {
315+
int diff = int(WritePrecision::NS) - int(point._tsWritePrecision);
316+
addZerosToTimestamp(point, diff*3);
317+
}
318+
}
319+
320+
bool InfluxDBClient::writePoint(Point & point) {
321+
if (point.hasFields()) {
322+
checkPrecisions(point);
295323
String line = pointToLineProtocol(point);
296324
return writeRecord(line);
297325
}
298326
return false;
299327
}
300328

329+
330+
301331
InfluxDBClient::Batch::Batch(uint16_t size):_size(size) {
302332
buffer = new char*[size];
303333
for(int i=0;i< _size; i++) {

src/InfluxDbClient.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Test;
5050
* Automaticaly retries failed writes during next write, if server is overloaded.
5151
*/
5252
class InfluxDBClient {
53+
friend class Test;
5354
public:
5455
// Creates InfluxDBClient unconfigured instance.
5556
// Call to setConnectionParams is required to set up client
@@ -221,7 +222,6 @@ class InfluxDBClient {
221222
virtual size_t write(uint8_t data) override;
222223

223224
};
224-
friend class Test;
225225
ConnectionInfo _connInfo;
226226
// Cached full write url
227227
String _writeUrl;
@@ -263,6 +263,10 @@ class InfluxDBClient {
263263
// flashOnlyFull - whether to flush only full batches
264264
// Returns true if successful, false in case of any error
265265
bool flushBufferInternal(bool flashOnlyFull);
266+
// Checks precision of point and mofifies if needed
267+
void checkPrecisions(Point & point);
268+
// helper which adds zeroes to timestamo of point to increase precision
269+
static void addZerosToTimestamp(Point &point, int zeroes);
266270
};
267271

268272

src/Options.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@ WriteOptions& WriteOptions::addDefaultTag(const String &name, const String &valu
3232
if(_defaultTags.length() > 0) {
3333
_defaultTags += ',';
3434
}
35-
_defaultTags += escapeKey(name);
35+
char *s = escapeKey(name);
36+
_defaultTags += s;
37+
delete [] s;
38+
s = escapeKey(value);
3639
_defaultTags += '=';
37-
_defaultTags += escapeKey(value);
40+
_defaultTags += s;
41+
delete [] s;
3842
return *this;
3943
}

src/Point.cpp

+35-15
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,39 @@
2828
#include "Point.h"
2929
#include "util/helpers.h"
3030

31-
Point::Point(const String & measurement):
32-
_measurement(escapeKey(measurement, false)),
33-
_tags(""),
34-
_fields(""),
35-
_timestamp("")
31+
Point::Point(const String & measurement)
3632
{
33+
_measurement = escapeKey(measurement, false);
34+
_timestamp = nullptr;
35+
_tsWritePrecision = WritePrecision::NoTime;
36+
}
3737

38+
Point::~Point() {
39+
delete [] _measurement;
40+
delete [] _timestamp;
3841
}
3942

4043
void Point::addTag(const String &name, String value) {
4144
if(_tags.length() > 0) {
4245
_tags += ',';
4346
}
44-
_tags += escapeKey(name);
47+
char *s = escapeKey(name);
48+
_tags += s;
49+
delete [] s;
4550
_tags += '=';
46-
_tags += escapeKey(value);
51+
s = escapeKey(value);
52+
_tags += s;
53+
delete [] s;
4754
}
4855

4956
void Point::addField(const String &name, long long value) {
50-
char buff[50];
57+
char buff[23];
5158
snprintf(buff, 50, "%lld", value);
5259
putField(name, String(buff)+"i");
5360
}
5461

5562
void Point::addField(const String &name, unsigned long long value) {
56-
char buff[50];
63+
char buff[23];
5764
snprintf(buff, 50, "%llu", value);
5865
putField(name, String(buff)+"i");
5966
}
@@ -110,7 +117,9 @@ void Point::putField(const String &name, const String &value) {
110117
if(_fields.length() > 0) {
111118
_fields += ',';
112119
}
113-
_fields += escapeKey(name);
120+
char *s = escapeKey(name);
121+
_fields += s;
122+
delete [] s;
114123
_fields += '=';
115124
_fields += value;
116125
}
@@ -121,7 +130,7 @@ String Point::toLineProtocol(const String &includeTags) const {
121130

122131
String Point::createLineProtocol(const String &incTags) const {
123132
String line;
124-
line.reserve(_measurement.length() + 1 + incTags.length() + 1 + _tags.length() + 1 + _fields.length() + 1 + _timestamp.length());
133+
line.reserve(strLen(_measurement) + 1 + incTags.length() + 1 + _tags.length() + 1 + _fields.length() + 1 + strLen(_timestamp));
125134
line += _measurement;
126135
if(incTags.length()>0) {
127136
line += ",";
@@ -160,22 +169,33 @@ void Point::setTime(WritePrecision precision) {
160169
setTime(getTimeStamp(&tv,0));
161170
break;
162171
case WritePrecision::NoTime:
163-
_timestamp = "";
172+
setTime((char *)nullptr);
164173
break;
165174
}
175+
_tsWritePrecision = precision;
166176
}
167177

168178
void Point::setTime(unsigned long long timestamp) {
169-
_timestamp = timeStampToString(timestamp);
179+
setTime(timeStampToString(timestamp));
180+
}
181+
182+
void Point::setTime(const String &timestamp) {
183+
setTime(cloneStr(timestamp.c_str()));
184+
}
185+
186+
void Point::setTime(const char *timestamp) {
187+
setTime(cloneStr(timestamp));
170188
}
171189

172-
void Point::setTime(const String &timestamp) {
190+
void Point::setTime(char *timestamp) {
191+
delete [] _timestamp;
173192
_timestamp = timestamp;
174193
}
175194

176195
void Point::clearFields() {
177196
_fields = (char *)nullptr;
178-
_timestamp = (char *)nullptr;
197+
delete [] _timestamp;
198+
_timestamp = nullptr;
179199
}
180200

181201
void Point:: clearTags() {

src/Point.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Point {
3939
friend class InfluxDBClient;
4040
public:
4141
Point(const String &measurement);
42+
virtual ~Point();
4243
// Adds string tag
4344
void addTag(const String &name, String value);
4445
// Add field with various types
@@ -62,6 +63,8 @@ friend class InfluxDBClient;
6263
void setTime(unsigned long long timestamp);
6364
// Set timestamp in offset since epoch (1.1.1970 00:00:00). Correct precision must be set InfluxDBClient::setWriteOptions.
6465
void setTime(const String &timestamp);
66+
// Set timestamp in offset since epoch (1.1.1970 00:00:00). Correct precision must be set InfluxDBClient::setWriteOptions.
67+
void setTime(const char *timestamp);
6568
// Clear all fields. Usefull for reusing point
6669
void clearFields();
6770
// Clear tags
@@ -71,19 +74,22 @@ friend class InfluxDBClient;
7174
// True if a point contains at least one tag
7275
bool hasTags() const { return _tags.length() > 0; }
7376
// True if a point contains timestamp
74-
bool hasTime() const { return _timestamp.length() > 0; }
77+
bool hasTime() const { return strLen(_timestamp) > 0; }
7578
// Creates line protocol with optionally added tags
7679
String toLineProtocol(const String &includeTags = "") const;
7780
// returns current timestamp
7881
String getTime() const { return _timestamp; }
7982
protected:
80-
String _measurement;
83+
char *_measurement;
8184
String _tags;
8285
String _fields;
83-
String _timestamp;
86+
char *_timestamp;
87+
WritePrecision _tsWritePrecision;
8488
protected:
8589
// method for formating field into line protocol
8690
void putField(const String &name, const String &value);
91+
// set timestamp
92+
void setTime(char *timestamp);
8793
// Creates line protocol string
8894
String createLineProtocol(const String &incTags) const;
8995
};

src/WritePrecision.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#ifndef _WRITE_PRECISION_H_
2828
#define _WRITE_PRECISION_H_
2929
// Enum WritePrecision defines constants for specifying InfluxDB write prcecision
30-
enum class WritePrecision {
30+
enum class WritePrecision:uint8_t {
3131
// Specifyies that points has no timestamp (default). Server will assign timestamp.
3232
NoTime = 0,
3333
// Seconds

src/util/debug.h

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929

3030
#include <Arduino.h>
3131

32+
// Uncomment bellow in case of a problem and rebuild sketch
33+
//#define INFLUXDB_CLIENT_DEBUG_ENABLE
34+
3235
#ifdef INFLUXDB_CLIENT_DEBUG_ENABLE
3336
# define INFLUXDB_CLIENT_DEBUG(fmt, ...) Serial.printf("%.03f ",millis()/1000.0f);Serial.printf_P( (PGM_P)PSTR(fmt), ## __VA_ARGS__ )
3437
#else

src/util/helpers.cpp

+36-25
Original file line numberDiff line numberDiff line change
@@ -68,36 +68,34 @@ unsigned long long getTimeStamp(struct timeval *tv, int secFracDigits) {
6868
return tsVal;
6969
}
7070

71-
String timeStampToString(unsigned long long timestamp) {
72-
static char buff[50];
73-
snprintf(buff, 50, "%llu", timestamp);
74-
return String(buff);
71+
char *timeStampToString(unsigned long long timestamp, int extraCharsSpace) {
72+
//22 is max long long string length (18)
73+
char *buff = new char[22+extraCharsSpace+1];
74+
snprintf(buff, 22, "%llu", timestamp);
75+
return buff;
7576
}
7677

77-
String escapeKey(const String &key, bool escapeEqual) {
78-
String ret;
79-
ret.reserve(key.length()+5); //5 is estimate of chars needs to escape,
78+
static char escapeChars[] = "=\r\n\t ,";
8079

81-
for (char c: key)
82-
{
83-
switch (c)
84-
{
85-
case '\r':
86-
case '\n':
87-
case '\t':
88-
case ' ':
89-
case ',':
90-
ret += '\\';
91-
break;
92-
case '=':
93-
if(escapeEqual) {
94-
ret += '\\';
95-
}
96-
break;
80+
char *escapeKey(const String &key, bool escapeEqual) {
81+
char c,*ret,*d,*s = (char *)key.c_str();
82+
int n = 0;
83+
while ((c = *s++)) {
84+
if(strchr(escapeEqual?escapeChars:escapeChars+1, c)) {
85+
n++;
9786
}
98-
ret += c;
9987
}
100-
return ret;
88+
ret = new char[key.length()+n+1];
89+
s = (char *)key.c_str();
90+
d = ret;
91+
while ((c = *s++)) {
92+
if (strchr(escapeEqual?escapeChars:escapeChars+1,c)) {
93+
*d++ = '\\';
94+
}
95+
*d++ = c;
96+
}
97+
*d = 0;
98+
return ret;
10199
}
102100

103101
String escapeValue(const char *value) {
@@ -175,3 +173,16 @@ uint8_t getNumLength(long long l) {
175173
} while(l);
176174
return c;
177175
}
176+
177+
char *cloneStr(const char *str) {
178+
char *ret = new char[strlen(str)+1];
179+
strcpy(ret, str);
180+
return ret;
181+
}
182+
183+
size_t strLen(const char *str) {
184+
if(!str) {
185+
return 0;
186+
}
187+
return strlen(str);
188+
}

0 commit comments

Comments
 (0)