Updated required libraries

Kai Lauterbach 9 months ago
parent 7a97677e0d
commit 417493c8ba

File diff suppressed because it is too large Load Diff

@ -0,0 +1,231 @@
* @file APDS-9930.h
* @brief Library for the SparkFun APDS-9930 breakout board
* @author Shawn Hymel (SparkFun Electronics)
* @copyright This code is public domain but you buy me a beer if you use
* this and we meet someday (Beerware license).
* This library interfaces the Avago APDS-9930 to Arduino over I2C. The library
* relies on the Arduino Wire (I2C) library. to use the library, instantiate an
* APDS9930 object, call init(), and call the appropriate functions.
#ifndef APDS9930_H
#define APDS9930_H
#include <Arduino.h>
/* Debug */
#define DEBUG 0
/* APDS-9930 I2C address */
#define APDS9930_I2C_ADDR 0x39
/* Command register modes */
#define REPEATED_BYTE 0x80
#define SPECIAL_FN 0xE0
/* Error code for returned values */
#define ERROR 0xFF
/* Acceptable device IDs */
#define APDS9930_ID_1 0x12
#define APDS9930_ID_2 0x39
/* Misc parameters */
#define FIFO_PAUSE_TIME 30 // Wait period (ms) between FIFO reads
/* APDS-9930 register addresses */
#define APDS9930_ENABLE 0x00
#define APDS9930_ATIME 0x01
#define APDS9930_PTIME 0x02
#define APDS9930_WTIME 0x03
#define APDS9930_AILTL 0x04
#define APDS9930_AILTH 0x05
#define APDS9930_AIHTL 0x06
#define APDS9930_AIHTH 0x07
#define APDS9930_PILTL 0x08
#define APDS9930_PILTH 0x09
#define APDS9930_PIHTL 0x0A
#define APDS9930_PIHTH 0x0B
#define APDS9930_PERS 0x0C
#define APDS9930_CONFIG 0x0D
#define APDS9930_PPULSE 0x0E
#define APDS9930_CONTROL 0x0F
#define APDS9930_ID 0x12
#define APDS9930_STATUS 0x13
#define APDS9930_Ch0DATAL 0x14
#define APDS9930_Ch0DATAH 0x15
#define APDS9930_Ch1DATAL 0x16
#define APDS9930_Ch1DATAH 0x17
#define APDS9930_PDATAL 0x18
#define APDS9930_PDATAH 0x19
#define APDS9930_POFFSET 0x1E
/* Bit fields */
#define APDS9930_PON 0b00000001
#define APDS9930_AEN 0b00000010
#define APDS9930_PEN 0b00000100
#define APDS9930_WEN 0b00001000
#define APSD9930_AIEN 0b00010000
#define APDS9930_PIEN 0b00100000
#define APDS9930_SAI 0b01000000
/* On/Off definitions */
#define OFF 0
#define ON 1
/* Acceptable parameters for setMode */
#define POWER 0
#define PROXIMITY 2
#define WAIT 3
#define ALL 7
/* LED Drive values */
#define LED_DRIVE_100MA 0
#define LED_DRIVE_50MA 1
#define LED_DRIVE_25MA 2
#define LED_DRIVE_12_5MA 3
/* Proximity Gain (PGAIN) values */
#define PGAIN_1X 0
#define PGAIN_2X 1
#define PGAIN_4X 2
#define PGAIN_8X 3
/* ALS Gain (AGAIN) values */
#define AGAIN_1X 0
#define AGAIN_8X 1
#define AGAIN_16X 2
#define AGAIN_120X 3
/* Interrupt clear values */
#define CLEAR_PROX_INT 0xE5
#define CLEAR_ALS_INT 0xE6
#define CLEAR_ALL_INTS 0xE7
/* Default values */
#define DEFAULT_PPULSE 0x08
#define DEFAULT_POFFSET 0 // 0 offset
#define DEFAULT_PILT 0 // Low proximity threshold
#define DEFAULT_PIHT 50 // High proximity threshold
#define DEFAULT_AILT 0xFFFF // Force interrupt for calibration
#define DEFAULT_AIHT 0
#define DEFAULT_PERS 0x22 // 2 consecutive prox or ALS for int.
/* ALS coefficients */
#define DF 52
#define GA 0.49
#define B 1.862
#define C 0.746
#define D 1.291
/* State definitions */
enum {
#ifdef _AVR_IO_H_
// Do not use this alias as it's deprecated
/* APDS9930 Class */
class APDS9930 {
/* Initialization methods */
bool init();
uint8_t getMode();
bool setMode(uint8_t mode, uint8_t enable);
/* Turn the APDS-9930 on and off */
bool enablePower();
bool disablePower();
/* Enable or disable specific sensors */
bool enableLightSensor(bool interrupts = false);
bool disableLightSensor();
bool enableProximitySensor(bool interrupts = false);
bool disableProximitySensor();
/* LED drive strength control */
uint8_t getLEDDrive();
bool setLEDDrive(uint8_t drive);
// uint8_t getGestureLEDDrive();
// bool setGestureLEDDrive(uint8_t drive);
/* Gain control */
uint8_t getAmbientLightGain();
bool setAmbientLightGain(uint8_t gain);
uint8_t getProximityGain();
bool setProximityGain(uint8_t gain);
bool setProximityDiode(uint8_t drive);
uint8_t getProximityDiode();
/* Get and set light interrupt thresholds */
bool getLightIntLowThreshold(uint16_t &threshold);
bool setLightIntLowThreshold(uint16_t threshold);
bool getLightIntHighThreshold(uint16_t &threshold);
bool setLightIntHighThreshold(uint16_t threshold);
/* Get and set interrupt enables */
uint8_t getAmbientLightIntEnable();
bool setAmbientLightIntEnable(uint8_t enable);
uint8_t getProximityIntEnable();
bool setProximityIntEnable(uint8_t enable);
/* Clear interrupts */
bool clearAmbientLightInt();
bool clearProximityInt();
bool clearAllInts();
/* Proximity methods */
bool readProximity(uint16_t &val);
/* Ambient light methods */
bool readAmbientLightLux(float &val);
bool readAmbientLightLux(unsigned long &val);
float floatAmbientToLux(uint16_t Ch0, uint16_t Ch1);
unsigned long ulongAmbientToLux(uint16_t Ch0, uint16_t Ch1);
bool readCh0Light(uint16_t &val);
bool readCh1Light(uint16_t &val);
/* Proximity Interrupt Threshold */
uint16_t getProximityIntLowThreshold();
bool setProximityIntLowThreshold(uint16_t threshold);
uint16_t getProximityIntHighThreshold();
bool setProximityIntHighThreshold(uint16_t threshold);
/* Raw I2C Commands */
bool wireWriteByte(uint8_t val);
bool wireWriteDataByte(uint8_t reg, uint8_t val);
bool wireWriteDataBlock(uint8_t reg, uint8_t *val, unsigned int len);
bool wireReadDataByte(uint8_t reg, uint8_t &val);
int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len);

Binary file not shown.


Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.


Width:  |  Height:  |  Size: 431 KiB

@ -0,0 +1,156 @@
* Copyright (C) 2008 The Android Open Source Project
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software< /span>
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
* extended sensor support to include color, voltage and current */
#ifndef ARDUINO
#include <stdint.h>
#elif ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#include "WProgram.h"
/* Intentionally modeled after sensors.h in the Android API:
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
/* Constants */
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */
#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */
#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */
#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */
/** Sensor types */
typedef enum
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */
} sensors_type_t;
/** struct sensors_vec_s is used to return a vector in a common format. */
typedef struct {
union {
float v[3];
struct {
float x;
float y;
float z;
/* Orientation sensors */
struct {
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */
float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */
int8_t status;
uint8_t reserved[3];
} sensors_vec_t;
/** struct sensors_color_s is used to return color data in a common format. */
typedef struct {
union {
float c[3];
/* RGB color space */
struct {
float r; /**< Red component */
float g; /**< Green component */
float b; /**< Blue component */
uint32_t rgba; /**< 24-bit RGBA value */
} sensors_color_t;
/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
int32_t version; /**< must be sizeof(struct sensors_event_t) */
int32_t sensor_id; /**< unique sensor identifier */
int32_t type; /**< sensor type */
int32_t reserved0; /**< reserved */
int32_t timestamp; /**< time is in milliseconds */
float data[4];
sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */
sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
sensors_vec_t orientation; /**< orientation values are in degrees */
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
float temperature; /**< temperature is in degrees centigrade (Celsius) */
float distance; /**< distance in centimeters */
float light; /**< light in SI lux units */
float pressure; /**< pressure in hectopascal (hPa) */
float relative_humidity; /**< relative humidity in percent */
float current; /**< current in milliamps (mA) */
float voltage; /**< voltage in volts (V) */
sensors_color_t color; /**< color in RGB component values */
} sensors_event_t;
/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
char name[12]; /**< sensor name */
int32_t version; /**< version of the hardware + driver */
int32_t sensor_id; /**< unique sensor identifier */
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
float max_value; /**< maximum value of this sensor's value in SI units */
float min_value; /**< minimum value of this sensor's value in SI units */
float resolution; /**< smallest difference between two values reported by this sensor */
int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */
} sensor_t;
class Adafruit_Sensor {
// Constructor(s)
Adafruit_Sensor() {}
virtual ~Adafruit_Sensor() {}
// These must be defined by the subclass
virtual void enableAutoRange(bool enabled) { (void)enabled; /* suppress unused warning */ };
virtual bool getEvent(sensors_event_t*) = 0;
virtual void getSensor(sensor_t*) = 0;
bool _autoRange;

@ -0,0 +1,229 @@
# Adafruit Unified Sensor Driver #
Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
## Unified Sensor Drivers ##
The following drivers are based on the Adafruit Unified Sensor Driver:
- [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345)
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
- [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library)
- [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U)
- [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561)
- [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library)
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
- [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified)
**Barometric Pressure**
- [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified)
- [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library)
**Humidity & Temperature**
- [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library)
**Humidity, Temperature, & Barometric Pressure**
- [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/)
- [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055)
**All in one device**
- [Adafruit_LSM9DS0](https://github.com/adafruit/Adafruit_LSM9DS0_Library) (accelerometer, gyroscope, magnetometer)
- [Adafruit_LSM9DS1](https://github.com/adafruit/Adafruit_LSM9DS1/) (accelerometer, gyroscope, magnetometer)
## How Does it Work? ##
Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values:
**Sensor Types (sensors\_type\_t)**
These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
/** Sensor types */
typedef enum
} sensors_type_t;
**Sensor Details (sensor\_t)**
This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
char name[12];
int32_t version;
int32_t sensor_id;
int32_t type;
float max_value;
float min_value;
float resolution;
int32_t min_delay;
} sensor_t;
The individual fields are intended to be used as follows:
- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2")
- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h
- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit)
- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit)
- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate
**Sensor Data/Events (sensors\_event\_t)**
This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
int32_t version;
int32_t sensor_id;
int32_t type;
int32_t reserved0;
int32_t timestamp;
float data[4];
sensors_vec_t acceleration;
sensors_vec_t magnetic;
sensors_vec_t orientation;
sensors_vec_t gyro;
float temperature;
float distance;
float light;
float pressure;
float relative_humidity;
float current;
float voltage;
sensors_color_t color;
} sensors_event_t;
It includes the following fields:
- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!)
- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h
- **timestamp**: time in milliseconds when the sensor value was read
- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
**Required Functions**
In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
bool getEvent(sensors_event_t*);
Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data.
void getSensor(sensor_t*);
Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
**Standardised SI values for sensors\_event\_t**
A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
- **acceleration**: values are in **meter per second per second** (m/s^2)
- **magnetic**: values are in **micro-Tesla** (uT)
- **orientation**: values are in **degrees**
- **gyro**: values are in **rad/s**
- **temperature**: values in **degrees centigrade** (Celsius)
- **distance**: values are in **centimeters**
- **light**: values are in **SI lux** units
- **pressure**: values are in **hectopascal** (hPa)
- **relative\_humidity**: values are in **percent**
- **current**: values are in **milliamps** (mA)
- **voltage**: values are in **volts** (V)
- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
## The Unified Driver Abstraction Layer in Practice ##
Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t).
An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below:
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
/* Get a new sensor event */
sensors_event_t event;
/* Display the results (light is measured in lux) */
if (event.light)
Serial.print(event.light); Serial.println(" lux");
/* If event.light = 0 lux the sensor is probably saturated
and no reliable data could be generated! */
Serial.println("Sensor overload");
Similarly, we can get the basic technical capabilities of this sensor with the following code:
sensor_t sensor;
sensor_t sensor;
/* Display the sensor details */
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");

@ -0,0 +1,176 @@
#include "Arduino.h"
#include "ESP8266Influxdb.h"
#include <ESP8266WiFi.h>
#define DEBUG_PRINT // comment this line to disable debug print
#define DEBUG_PRINT(a)
#define DEBUG_PRINT(a) (Serial.println(String(F("[Debug]: "))+(a)))
#define _DEBUG
Influxdb::Influxdb(const char *host, uint16_t port) : WiFiClient() {
_port = port;
_host = host;
DB_RESPONSE Influxdb::opendb(String db, String user, String password) {
_db = "db=" + db + "&u=" + user + "&p=" + password;
DB_RESPONSE Influxdb::opendb(String db) {
_db = "db=" + db;
DB_RESPONSE Influxdb::write(FIELD data) {
return write(data.postString());
DB_RESPONSE Influxdb::write(String data) {
if (!connect(_host, _port)) {
DEBUG_PRINT("connection failed");
_response = DB_CONNECT_FAILED;
return _response;
String postHead = "POST /write?" + _db + " HTTP/1.1\r\n";
postHead += "Host: " + String(_host) + ":" + String(_port) + "\r\n";
// postHead += "Content-Type: application/x-www-form-urlencoded\r\n";
postHead += "Content-Length: " + String(data.length()) + "\r\n\r\n";
DEBUG_PRINT("Writing data to " + String(_host) + ":" + String(_port));
print(postHead + data);
DEBUG_PRINT(postHead + data);
uint8_t t = 0;
// Check the reply whether writing is success or not
while (!available() && t < 200) {
if (t==200) {_response = DB_ERROR; return DB_ERROR; } // Return error if time out.
#if !defined _DEBUG
if (available()) {
_response = (findUntil("204", "\r")) ? DB_SUCCESS : DB_ERROR;
return _response;
while (available()) {
String line = readStringUntil('\n');
if (line.substring(9,12)=="204")
_response = DB_SUCCESS;
DEBUG_PRINT("(Responsed): " + line);
return _response;
return DB_ERROR;
DB_RESPONSE Influxdb::query(String sql) {
if (!connect(_host, _port)) {
DEBUG_PRINT("connection failed");
_response = DB_CONNECT_FAILED;
return _response;
String url = "/query?";
#if defined _DEBUG
url += "pretty=true&";
url += _db;
url += "&q=" + URLEncode(sql);
DEBUG_PRINT("Requesting URL: ");
// This will send the request to the server
print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + _host +
":" + _port + "\r\n" + "Connection: close\r\n\r\n");
// Read all the lines of the reply from server and print them to Serial
uint8_t t = 0;
while (!available() && t < 200) {
if (t==200) {_response = DB_ERROR; return DB_ERROR; } // Return error if time out.
uint8_t i=0;
String line = readStringUntil('\n');
DEBUG_PRINT("[HEAD] " + line);
if (line.substring(9,12) == "200") {
while (available()) {
line = readStringUntil('\n');
DEBUG_PRINT("(HEAD) " + line);
if (i < 6 ) i++; else return _response;
_response = DB_SUCCESS;
_response = DB_ERROR;
#if defined _DEBUG
while (available()) {
line = readStringUntil('\n');
DEBUG_PRINT("[HEAD] " + line);
return _response;
DB_RESPONSE Influxdb::response() {
return _response;
/* -----------------------------------------------*/
// Field object
/* -----------------------------------------------*/
FIELD::FIELD(String m) {
measurement = m;
void FIELD::empty() {
_data = "";
_tag = "";
void FIELD::addTag(String key, String value) {
_tag += "," + key + "=" + value;
void FIELD::addField(String key, float value) {
_data = (_data == "") ? (" ") : (_data += ",");
_data += key + "=" + String(value);
String FIELD::postString() {
// uint32_t utc = 1448114561 + millis() /1000;
return measurement + _tag + _data;
// URL Encode with Arduino String object
String URLEncode(String msg) {
const char *hex = "0123456789abcdef";
String encodedMsg = "";
uint16_t i;
for (i = 0; i < msg.length(); i++) {
if (('a' <= msg.charAt(i) && msg.charAt(i) <= 'z') ||
('A' <= msg.charAt(i) && msg.charAt(i) <= 'Z') ||
('0' <= msg.charAt(i) && msg.charAt(i) <= '9')) {
encodedMsg += msg.charAt(i);
} else {
encodedMsg += '%';
encodedMsg += hex[msg.charAt(i) >> 4];
encodedMsg += hex[msg.charAt(i) & 15];
return encodedMsg;

@ -0,0 +1,72 @@
/* Influxdb library
MIT license
Written by HW Wong
#ifndef INFLUXDB_H
#define INFLUXDB_H
#include "Arduino.h"
#include <ESP8266WiFi.h>
// Url encode function
String URLEncode(String msg);
class FIELD
FIELD(String m);
String measurement;
void addField(String key, float value);
void addTag(String key, String value);
void empty();
String postString();
String _data;
String _tag;
class Influxdb : private WiFiClient
Influxdb(const char* host, uint16_t port);
DB_RESPONSE opendb(String db);
DB_RESPONSE opendb(String db, String user, String password);
DB_RESPONSE write(FIELD data);
DB_RESPONSE write(String data);
DB_RESPONSE query(String sql);
//uint8_t createDatabase(char *dbname);
DB_RESPONSE response();
using WiFiClient::available;
using WiFiClient::read;
using WiFiClient::flush;
using WiFiClient::find;
using WiFiClient::findUntil;
using WiFiClient::peek;
using WiFiClient::readBytes;
using WiFiClient::readBytesUntil;
using WiFiClient::readString;
using WiFiClient::readStringUntil;
using WiFiClient::parseInt;
using WiFiClient::setTimeout;
uint16_t _port;
const char* _host;
String _db;
DB_RESPONSE _response;

@ -0,0 +1,24 @@
# Syntax Coloring Map For ESP8266 Influxdb library
# Datatypes (KEYWORD1)
Influxdb KEYWORD1
# Methods and Functions (KEYWORD2)
addField KEYWORD2
empty KEYWORD2
opendb KEYWORD2
write KEYWORD2
query KEYWORD2
postString KEYWORD2
response KEYWORD2

@ -0,0 +1,148 @@
# Changelog
## 3.12.1 [2022-08-29]
### Fixes
- [193](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/193) - Automatically adjusting point timestamp according to the setting of write precision.
## 3.12.0 [2022-03-21]
### Features
- [185](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/185) - Added diagnostic server connection state getter `bool InfluxDBClient::isConnected()`
## 3.11.0 [2022-02-18]
### Features
- [174](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/174),[181](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/181) - All API methods with a string param allow specifying string by all basic types:
- Arduino `String` class
- C `char *` or `char[]`
- Flash string using `F`,`PSTR` or `FPSTR` macros
### Fixes
- [176](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/176) - Cleared all compiler warnings
## 3.10.0 [2022-01-20]
### Features
- [167](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/167) - Added `InfluxDBClient::writeRecord(const char *record)`.
- [167](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/167) - Added possibility to disable retrying by setting `maxRetryAttempts` to zero: `client.setWriteOptions(WriteOptions().maxRetryAttempts(0));`
- [172](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/172) - Added directly streaming batch for write. It can be enabled by `InfluxDBClient::setStreamWrite(bool enable = true)`. Writing by streaming lines of batch saves RAM as it sends data without allocating a buffer. On the other hand, this way of writing is about half times slower than the classic way, when allocating the buffer for writing the whole batch.
- [172](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/172) - Allowing larger batch size, > 255.
- [173](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/173) - Added Flux query parameters. Now supported by InfluxDB Cloud only.
## 3.9.0 [2021-09-17]
### Features
- [#147](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/147) - Updated InfluxDB 2 Cloud CA root certificate to _ISRG Root X1_.
Current InfluxDB 2 Cloud CA root certificate _DST Root CA X3_ expires on September 30th 2021!
- [#157](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/157) - Added Buckets sub-client for managing buckets in InfluxDB 2.
### Fixes
- [#150](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/150) - `HTTPOptions::httpReadTimeout` is also set as the connect timeout for HTTP connection on ESP32. It also works for HTTPS connection since ESP32 Arduino Core 2.0.0.
- [#156](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/156) - Correctly rounding _writeBufferSize_, when _bufferSize/batchSize >= 256_.
- [#162](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/162) - Fixed flushing of not full buffer after the flush timeout.
### Documentation
- [#163](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/163) - More precise description of supported devices.
## 3.8.0 [2021-04-01]
### Features
- [#143](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/143) - `InfluxDBClient::setInsecure` now works also for ESP32. Requires Arduino ESP32 SDK 1.0.5 or higher
### Documentation
- [#134](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/134):
- Added untrusted connection (skipping certificate validation) info to Readme
- `SecureWrite` and `SecureBatchWrite` demos enhanced with example about using untrusted connection
- Various fixes of typos
### Fixes
- [#137](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/137) - Fixed parsing Flux response with unexpected annotations
## 3.7.0 [2020-12-24]
### Features
- [#125](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/124) - Added credentials to the InfluxDB 1.x validation endpoint (/ping). To leverage this, [enable ping authentication](https://docs.influxdata.com/influxdb/v1.8/administration/config/#ping-auth-enabled-false)
### Fixes
- [#129](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/129) - Updated InfluxDB 2 Cloud CA certificate to trust servers from all cloud providers (AWS, Azure, GCP)
## 3.6.1 [2020-11-30]
### Features
### Fixes
- [#121](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/121) - Fixed compile error in case of warning is treated as an error
- [#122](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/122) - Deleting WiFiClient instance to avoid memory leaking when the InfluxDBClient is reinitialized
- [#124](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/124) - Fixed compilation warnings
### Doc
- [#120](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/120) - Improved language wording in the Readme
## 3.6.0 [2020-11-10]
### Features
- [#117](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/117) - Added `InfluxDBClient::pointToLineProtocol(const Point& point)` for simple creation of InfluxDB line-protocol string with respect to default tags
### Fixes
- [#114](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/114) - Renamed `getRemaingRetryTime()`->`getRemainingRetryTime()`
- [#115](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/115) - Restored writing capability after a connection failure
- [#118](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/118) - Added escaping of URL params (org, bucker, V1 username and pass)
## 3.5.0 [2020-10-30]
### Features
- [#107](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/107) - Added possibility to set default tags. Use `WriteOptions::addDefaultTag()` to add a tag that will be added to each written point using the `writePoint()` function.
- [#109](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/109) - Retry strategy improvements:
- Added `canSendRequest()` function to check if retry strategy is applied
- Added `getRemaingRetryTime()` function to get wait time before another request (write/query) can be sent
- Removed applying retry wait time in case of network error
- Better explanatory error message when a request is about to be sent in the retry wait state
### Fixes
- [#108](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/108) - Added optional param for specifying decimal places of double.: `void Point::addField(String name, double value, int decimalPlaces = 2)`
- [#111](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/111) - Fixed blocked writing after another point reached max retry count (#110)
## 3.4.0 [2020-10-02]
### Features
- [#89](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/89) - ESP8266 only - Added Max Fragment Length Negotiation for TLS communication to reduce memory allocation. If server supports MFLN, it saves ~10kB. Standalone InfluxDB OSS server doesn't support MFLN, Cloud yes. To leverage MFLN for standalone OSS, a reverse proxy needs to be used.
- [#91](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/91) - Improved API for settings of write and HTTP options:
- 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.
- 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.
- Added possibility to set HTTP response read timeout (part of the `HTTPOptions`).
- 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.
- [#93](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/93) - Write logic improvements
- Retry on failure logic unification with other InfluxDB clients (exponential retry, max retry count 3, max retry interval)
- Better write buffer memory management
### Documentation
- [#87](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/87) - Fixed include file name in the Readme
- [#99](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/99) - Changed default InfluxDB 2 port from 9999 to 8086 (default since InfluxDB 2 RC0)
### Fixes
- [#90](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/90) - Fixed boolean type recognition of InfluxDB Flux
- [#101](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/101) - Better memory efficient point line composition
## Version 3.3.0 (2020-07-07)
- [NEW] Added possibility skip server certification validation (`setInsecure()` method)
- [NEW] Added possibility to query flux on secured InfluxDB 1.8 using V1 approach
- [NEW] `validateConnection()` can be used also for the [forward compatibility](https://docs.influxdata.com/influxdb/latest/tools/api/#influxdb-2-0-api-compatibility-endpoints) connection to InfluxDB 1.8
- [FIX] More precise default timestamp generating, up to microseconds
- [FIX] Debug compilation error
- [FIX] SecureBatchWrite compile error
## Version 3.2.0 (2020-06-09)
- [NEW] Added possibility to read data from InfluxDB using Flux queries
- [NEW] `timeSync` utility function for synchronous time synchronization using NTP
- [FIX] Properly initialize member variable (#59)
- [FIX] ASCII chars & compilation warning fix (#60)
- [Update] ESP8266 SDK 2.7+ required
## Version 3.1.3 (2020-04-27)
- [FIX] SecureWrite crash (#54)
## Version 3.1.2 (2020-04-18)
- [FIX] Compilation error on fields order (#43)
- [FIX] Invalid precision constant for microseconds (#49)
- [FIX] Write error in case point has no tags (#50)
## Version 3.1.1 (2020-04-06)
- [Updated] CA Certificate for SSL (#38)
## Version 3.1.0 (2020-03-12)
- [NEW] Added User-agent header
- [FIX] status code check when pinging an InfluxDB version 1.x instance
## Version 3.0.0 (2020-02-11)
- New API with similar keywords as other official InfluxDB clients
- Richer set of data types for fields and timestamp methods
- Advanced features, such as implicit batching, automatic retrying on server back-pressure and connection failure, along with secured communication over TLS supported for both devices and authentication
- Special characters escaping
- Backward support for original API of V1/V2

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2020 Tobias Schürg, InfluxData
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

@ -0,0 +1,696 @@
# InfluxDB Arduino Client
Simple Arduino client for writing and reading data from [InfluxDB](https://www.influxdata.com/products/influxdb-overview/), no matter whether it is a local server or InfluxDB Cloud. The library supports authentication, secure communication over TLS, [batching](#writing-in-batches), [automatic retrying](#buffer-handling-and-retrying) on server back-pressure and connection failure.
It also allows setting data in various formats, automatically escapes special characters and offers specifying timestamp in various precisions.
Library supports both [InfluxDB 2](#basic-code-for-influxdb-2) and [InfluxDB 1](#basic-code-for-influxdb-2).
This is a new implementation and the API, [original API](#original-api) is still supported.
Supported devices:
- ESP8266 with [Arduino core for ESP8266](https://github.com/esp8266/Arduino) at least version [3.0.2](https://github.com/esp8266/Arduino/releases/tag/3.0.2).
- ESP32 with [Arduino core for the ESP32](https://github.com/espressif/arduino-esp32) at least version [2.0.2](https://github.com/espressif/arduino-esp32/releases/tag/2.0.2).
This library doesn't support using those devices as a peripheral.
:warning: Only connection over internal WiFi capability is supported for now.
## Table of contents
- [InfluxDB Arduino Client](#influxdb-arduino-client)
- [Basic code for InfluxDB 2](#basic-code-for-influxdb-2)
- [Basic code for InfluxDB 1](#basic-code-for-influxdb-1)
- [Connecting to InfluxDB Cloud 2](#connecting-to-influxdb-cloud-2)
- [Writing in Batches](#writing-in-batches)
- [Timestamp](#timestamp)
- [Configure Time](#configure-time)
- [Batch Size](#batch-size)
- [Large Batch Size](#large-batch-size)
- [Write Modes](#write-modes)
- [Buffer Handling and Retrying](#buffer-handling-and-retrying)
- [Write Options](#write-options)
- [HTTP Options](#http-options)
- [Secure Connection](#secure-connection)
- [InfluxDb 2](#influxdb-2)
- [InfluxDb 1](#influxdb-1)
- [Skipping certificate validation](#skipping-certificate-validation)
- [Querying](#querying)
- [Parametrized Queries](#parametrized-queries)
- [Original API](#original-api)
- [Initialization](#initialization)
- [Sending a single measurement](#sending-a-single-measurement)
- [Write multiple data points at once](#write-multiple-data-points-at-once)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)
## Basic code for InfluxDB 2
After [setting up an InfluxDB 2 server](https://docs.influxdata.com/influxdb/v2.0/get-started/), first define connection parameters and a client instance:
// InfluxDB 2 server url, e.g. (Use: InfluxDB UI -> Load Data -> Client Libraries)
#define INFLUXDB_URL "influxdb-url"
// InfluxDB 2 server or cloud API authentication token (Use: InfluxDB UI -> Load Data -> Tokens -> <select token>)
#define INFLUXDB_TOKEN "token"
// InfluxDB 2 organization name or id (Use: InfluxDB UI -> Settings -> Profile -> <name under tile> )
#define INFLUXDB_ORG "org"
// InfluxDB 2 bucket name (Use: InfluxDB UI -> Load Data -> Buckets)
#define INFLUXDB_BUCKET "bucket"
// Single InfluxDB instance
The next step is adding data. A single row of data is represented by the `Point` class. It consists of a measurement name (like a table name), tags (which labels data) and fields ( the values to store):
// Define data point in the measurement named 'device_status`
Point pointDevice("device_status");
// Set tags
pointDevice.addTag("device", "ESP8266");
pointDevice.addTag("SSID", WiFi.SSID());
// Add data fields
pointDevice.addField("rssi", WiFi.RSSI());
pointDevice.addField("uptime", millis());
And finally, write the data to the database:
// Write data
Complete source code is available in the [BasicWrite example](examples/BasicWrite/BasicWrite.ino).
Data can be seen in the InfluxDB UI immediately. Use the [Data Explorer](https://docs.influxdata.com/influxdb/v2.0/query-data/execute-queries/data-explorer/) or create a [Dashboard](https://docs.influxdata.com/influxdb/v2.0/visualize-data/dashboards/).
## Basic code for InfluxDB 1
Using InfluxDB Arduino client for InfluxDB 1 is almost the same as for InfluxDB 2. The only difference is that InfluxDB 1 uses _database_ as classic name for data storage instead of bucket and the server is unsecured by default.
There is also a different `InfluxDBClient constructor` and `setConnectionParametersV1` function for setting the security params. Everything else remains the same.
// InfluxDB server url, e.g. (don't use localhost, always server name or ip address)
#define INFLUXDB_URL "influxdb-url"
// InfluxDB database name
#define INFLUXDB_DB_NAME "database"
// Single InfluxDB instance
// Define data point with measurement name 'device_status`
Point pointDevice("device_status");
// Set tags
pointDevice.addTag("device", "ESP8266");
pointDevice.addTag("SSID", WiFi.SSID());
// Add data
pointDevice.addField("rssi", WiFi.RSSI());
pointDevice.addField("uptime", millis());
// Write data
Complete source code is available in [BasicWrite example](examples/BasicWrite/BasicWrite.ino)
## Connecting to InfluxDB Cloud 2
Instead of setting up a local InfluxDB 2 server, it is possible to quickly [start with InfluxDB Cloud 2](https://docs.influxdata.com/influxdb/cloud/get-started/) with a [Free Plan](https://docs.influxdata.com/influxdb/cloud/account-management/pricing-plans/#free-plan).
InfluxDB Cloud uses secure communication over TLS (https). We need to tell the client to trust this connection. The paragraph bellow describes how to set trusted connection. However, InfluxDB cloud servers have only 3 months validity period. Their CA certificate, included in this library, is valid until 2035. Check [Skipping certification validation](#skipping-certificate-validation) for more details.
Connecting an Arduino client to InfluxDB Cloud server requires a few additional steps comparing to connecting to local server.
Connection parameters are almost the same as above, the only difference is that server URL now points to the InfluxDB Cloud 2, you set up after you've finished creating an InfluxDB Cloud 2 subscription. You will find the correct server URL in `InfluxDB UI -> Load Data -> Client Libraries`.
//Include also InfluxCloud 2 CA certificate
#include <InfluxDbCloud.h>
// InfluxDB 2 server or cloud url, e.g. https://eu-central-1-1.aws.cloud2.influxdata.com (Use: InfluxDB UI -> Load Data -> Client Libraries)
#define INFLUXDB_URL "influxdb-url"
// InfluxDB 2 server or cloud API authentication token (Use: InfluxDB UI -> Load Data -> Tokens -> <select token>)
#define INFLUXDB_TOKEN "token"
// InfluxDB 2 organization name or id (Use: InfluxDB UI -> Settings -> Profile -> <name under tile> )
#define INFLUXDB_ORG "org"
// InfluxDB 2 bucket name (Use: InfluxDB UI -> Load Data -> Buckets)
#define INFLUXDB_BUCKET "bucket"
You need to pass an additional parameter to the client constructor, which is a certificate of the server to trust. The constant `InfluxDbCloud2CACert` contains the InfluxDB Cloud 2 CA certificate, which is predefined in this library:
// Single InfluxDB instance
Read more about [secure connection](#secure-connection).
Additionally, time needs to be synced:
// Synchronize time with NTP servers and set timezone
// Accurate time is necessary for certificate validation and writing in batches
// For the fastest time sync find NTP servers in your area: https://www.pool.ntp.org/zone/
configTzTime(TZ_INFO "pool.ntp.org", "time.nis.gov");
Read more about time synchronization in [Configure Time](#configure-time).
Defining data and writing it to the DB is the same as in the case of [BasicWrite](#basic-code):
// Define data point with measurement name 'device_status`
Point pointDevice("device_status");
// Set tags
pointDevice.addTag("device", "ESP8266");
pointDevice.addTag("SSID", WiFi.SSID());
// Add data
pointDevice.addField("rssi", WiFi.RSSI());
pointDevice.addField("uptime", millis());
// Write data
Complete source code is available in [SecureWrite example](examples/SecureWrite/SecureWrite.ino).
## Writing in Batches
InfluxDB client for Arduino can also write data in batches. A batch is simply a set of points that will be sent at once. To create a batch, the client will keep all points until the number of points reaches the batch size and then it will write all points at once to the InfluxDB server. This is often more efficient than writing each point separately.
### Timestamp
If using batch writes, the timestamp should be employed. Timestamp specifies the time when data was gathered and it is used in the form of a number of seconds (milliseconds, etc) from epoch (1.1.1970) UTC.
If points have no timestamp assigned, InfluxDB assigns a timestamp at the time of writing, which could happen much later than the data has been obtained, because the final batch write will happen when the batch is full (or when [flush buffer](#buffer-handling-and-retrying) is forced).
InfluxDB allows sending timestamps in various precisions - nanoseconds, microseconds, milliseconds or seconds. The milliseconds precision is usually enough for using on Arduino. The maximum available precision is microseconds. Setting the timestamp to nanoseconds will just add zeroes for microseconds fraction and will not improve timestamp accuracy.
The client has to be configured with a time precision. The default settings is to not use the timestamp, which means that the server will assign a timestamp when the data is written to the database. The `setWriteOptions` functions allows setting custom `WriteOptions` params and one of them is __write precision__:
``` cpp
// Set write precision to milliseconds. Leave other parameters default.
When a write precision is configured, the client will automatically assign the current time to the timestamp of each written point which doesn't have a timestamp assigned.
If you want to manage timestamp on your own, there are several ways to set the timestamp explicitly.
- `setTime(WritePrecision writePrecision)` - Sets the timestamp to the actual time in the desired precision. The same precision must set in WriteOptions.
- `setTime(unsigned long long timestamp)` - Sets the timestamp to an offset since the epoch. Correct precision must be set InfluxDBClient::setWriteOptions.
- `setTime(String timestamp)` - Sets the timestamp to an offset since the epoch. Correct precision must be set InfluxDBClient::setWriteOptions.
The `getTime()` method allows copying the timestamp between points.
### Configure Time
Dealing with timestamps, and also validating server or CA certificate, requires that the device has correctly set the time. This can be done with one line of code:
// Synchronize time with NTP servers and set timezone
// Accurate time is necessary for certificate validation and writing in batches
// For the fastest time sync find NTP servers in your area: https://www.pool.ntp.org/zone/
configTzTime("PST8PDT", "pool.ntp.org", "time.nis.gov");
The `configTzTime` function starts the time synchronization with NTP servers. The first parameter specifies the timezone information, which is important for distinguishing between UTC and a local timezone and for daylight saving changes.
The last two string parameters are the internet addresses of NTP servers. Check [pool.ntp.org](https://www.pool.ntp.org/zone) for address of some local NTP servers.
Timezone string details are described at [https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html](https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html).
Values for some timezones:
- Central Europe: `CET-1CEST,M3.5.0,M10.5.0/3`
- Eastern: `EST5EDT`
- Japanese: `JST-9`
- Pacific Time: `PST8PDT`
There is also another function for syncing the time, which takes timezone and DST offset. As DST info is set via static offset it will create local time problem when DST change occurs.
It's declaration is following:
configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
In the example code it would be:
// Synchronize time with NTP servers
// Accurate time is necessary for certificate validation and writing in batches
configTime(3600, 3600, "pool.ntp.org", "time.nis.gov");
Both `configTzTime` and `configTime` functions are asynchronous. This means that calling the functions just starts the time synchronization. Time is often not synchronized yet upon returning from call.
There is a helper function `timeSync` provided with the this library. The function starts time synchronization by calling the `configTzTime` and waits maximum 20 seconds for time to be synchronized. It prints progress info and final local time to the `Serial` console.
`timeSync` has the same signature as `configTzTime` and it is included with the main header file `InfluxDbClient.h`:
// Synchronize time with NTP servers and waits for competition. Prints waiting progress and final synchronized time to the Serial.
// Accurate time is necessary for certificate validation and writing points in batch
// For the fastest time sync find NTP servers in your area: https://www.pool.ntp.org/zone/
void timeSync(const char *tzInfo, const char* ntpServer1, const char* ntpServer2 = nullptr, const char* ntpServer3 = nullptr);
### Batch Size
Setting batch size depends on data gathering and DB updating strategy.
If data is written in short periods (seconds), the batch size should be set according to your expected write periods and update frequency requirements.
For example, if you would like to see updates (on the dashboard or in processing) each minute and you are measuring a single value (1 point) every 10s (6 points per minute), the batch size should be 6. If it is sufficient to update each hour and you are creating 1 point each minute, your batch size should be 60.
In cases where the data should be written in longer periods and gathered data consists of several points, the batch size should be set to the expected number of points to be gathered.
To set the batch size we use `WriteOptions` object and [setWriteOptions](#write-options) function:
// Enable lines batching
Writing the point will add a point to the underlying buffer until the batch size is reached:
// Write first point to the buffer
// Buffered write always returns `true`
// Write second point to the buffer
// Write ninth point to the buffer
// Writing tenth point will cause flushing buffer and returns actual write result.
if(!client.writePoint(point10)) {
Serial.print("InfluxDB write failed: ");
In case cases where the number of points is not always the same, set the batch size to the maximum number of points and use the `flushBuffer()` function to force writing to the database. See [Buffer Handling](#buffer-handling-and-retrying) for more details.
### Large batch size
The maximum batch size depends on the available RAM of the device (~45KB for ESP8266 and ~260KB for ESP32). Larger batch size, >100 for ESP8255, >2000 for ESP32, must be chosen carefully to not crash the app with out of memory error. The Stream write mode must be used, see [Write Modes](#write-modes)
Always determine your typical line length using `client.pointToLineProtocol(point).length()`. For example, ESP32 can handle 2048 lines with an average length of 69. When the length of line or batch size is increased, the device becomes unstable, even there is more than 76k, it cannot send data or even crashes. ESP8266 handles successfully 330 of such lines.
:warning: Thoroughly test your app when using large batch files.
### Write Modes
Client has two modes of writing:
- Buffer (default)
- Stream
Writing is performed the way that client keeps written lines (points) separately and when a batch is completed, it allocates a data buffer for sending to a server via WiFi Client.
This is the fastest way to write data but requires some amount of free memory. Thus a big batch size cannot be used.
Another way of writing is *stream write*.
// Enables stream write
In this mode client continuously streams lines from batch to WiFi Client. No buffer allocation. As lines are allocated separately, it avoids problems with max allocable block size. The downside is, that writing is about 50% slower than in the Buffer mode.
## Buffer Handling and Retrying
InfluxDB contains an underlying buffer for handling writing in batches and automatic retrying on server back-pressure and connection failure.
Its size is controlled by the `bufferSize` param of [WriteOptions](#write-options) object:
// Increase buffer to allow caching of failed writes
The recommended size is at least 2 x batch size.
The state of the buffer can be determined via two functions:
- `isBufferEmpty()` - Returns true if buffer is empty
- `isBufferFull()` - Returns true if buffer is full
A full buffer can occur when there is a problem with the internet connection or the InfluxDB server is overloaded. In such cases, points to write remain in the buffer. When more points are added and connection problem remains, the buffer will reach the top and new points will overwrite older points.
Each attempt to write a point will try to send older points in the buffer. So, the `isBufferFull()` function can be used to skip low priority points.
The `flushBuffer()` function can be used to force writing, even if the number of points in the buffer is lower than the batch size. With the help of the `isBufferEmpty()` function a check can be made before a device goes to sleep:
// Check whether buffer in not empty
if (!client.isBufferEmpty()) {
// Write all remaining points to db
Other functions for dealing with buffer:
- `checkBuffer()` - Checks point buffer status and flushes if the number of points reaches batch size or flush interval runs out. This is the main function for controlling the buffer and it is used internally.
- `resetBuffer()` - Clears the buffer.
Check [SecureBatchWrite example](examples/SecureBatchWrite/SecureBatchWrite.ino) for example code of buffer handling functions.
## Write Options
Writing points can be controlled via `WriteOptions`, which is set in the `setWriteOptions` function:
| Parameter | Default Value | Meaning |
| writePrecision | `WritePrecision::NoTime` | Timestamp precision of written data |
| batchSize | `1` | Number of points that will be written to the database at once |
| 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 |
| flushInterval | `60` | Maximum time(in seconds) data will be held in buffer before points are written to the db |
| retryInterval | `5` | Default retry interval in sec, if not sent by server. Value `0` disables retrying |
| maxRetryInterval | `300` | Maximum retry interval in sec |
| maxRetryAttempts | `3` | Maximum count of retry attempts of failed writes |
## HTTP Options
`HTTPOptions` controls some aspects of HTTP communication and they are set via `setHTTPOptions` function:
| Parameter | Default Value | Meaning |
| connectionReuse | `false` | Whether HTTP connection should be kept open after initial communication. Usable for frequent writes/queries. |
| httpReadTimeout | `5000` | Timeout (ms) for reading server response |
## Secure Connection
Connecting to a secured server requires configuring the client to trust the server. This is achieved by providing the client with a server certificate, certificate authority certificate or certificate SHA1 fingerprint.
:memo: In ESP32 arduino SDK (1.0.4), `WiFiClientSecure` doesn't support fingerprint to validate the server certificate.
The certificate (in PEM format) or SHA1 fingerprint should be placed in flash memory to save RAM.
Code bellow is an example certificate in PEM format. Valid InfluxDB 2 Cloud CA certificate is included in the library in the constant `InfluxDbCloud2CACert`, located in the `InfluxDBCloud.h`.
You can use a custom server certificate by exporting it, e.g. using a web browser:
// Server certificate in PEM format, placed in the program (flash) memory to save RAM
const char ServerCert[] PROGMEM = R"EOF(
// Alternatively, use a fingerprint of server certificate to set trust. Works only for ESP8266.
const char ServerCert[] PROGMEM = "cabd2a79a1076a31f21d253635cb039d4329a5e8";
### InfluxDb 2
There are two ways to set the certificate or fingerprint to trust a server:
- Use full param constructor
// InfluxDB client instance with preconfigured InfluxCloud certificate
- Use `setConnectionParams` function:
// InfluxDB client instance
InfluxDBClient client;
void setup() {
// configure client
### InfluxDb 1
Use `setConnectionParamsV1` function:
// InfluxDB client instance
InfluxDBClient client;
void setup() {
// configure client
Another important prerequisite to successfully validate a server or CA certificate is to have properly synchronized time. More on this in [Configure Time](#configure-time).
:information_source: Time synchronization is not required for validating server certificate via SHA1 fingerprint.
### Skipping certificate validation
The CA certificate provided with the library is ISRG Root X1. This certificate lasts a very long time, until 2035. It is not necessary to update your device until then when using ISRG Root X1.
If you are using your own certificate, plase keep in mind server certificates have limited validity period, often only a few months. It will be necessary to frequently change trusted certificate in the source code and reflashing the device. A solution could be using OTA update, but you will still need to care about certificate validity and updating it ahead of time to avoid connection failures.
The best way to prevent frequent updates is to use a root certificate like the one provided with the library. If you are unable to use a root certificate from a trusted authority, you may want to use insecure mode instead. This is done with the help of `InfluxDBClient::setInsecure()` method.
You will also save space in flash (and RAM) by leaving certificate param empty when calling constructor or `setConnectionParams` method.
:memo: The `InfluxDBClient::setInsecure()` method must be called before calling any function that will establish connection. The best place to call it is in the `setup` method:
// InfluxDB client instance without a server certificate
void setup() {
// Set insecure connection to skip server certificate validation
:warning: Using untrusted connection is a security risk.
## Querying
InfluxDB 2 and InfluxDB 1.7+ (with [enabled flux](https://docs.influxdata.com/influxdb/latest/administration/config/#flux-enabled-false)) uses [Flux](https://www.influxdata.com/products/flux/) to process and query data. InfluxDB client for Arduino offers a simple, but powerful, way how to query data with `query` function. It parses response line by line, so it can read a huge responses (thousands data lines), without consuming a lot device memory.
The `query` returns `FluxQueryResult` object, which parses response and provides useful getters for accessing values from result set.
The InfluxDB flux query result set is returned in CSV format. In the example below, the first line contains type information and the second column names, and the rest is data:
Accessing data using `FluxQueryResult` requires knowing the query result structure, especially the name and the type of the column. The best practice is to tune the query
in the `InfluxDB Data Explorer` and use the final query with this library.
Browsing thought the result set is done by repeatedly calling the `next()` method, until it returns false. Unsuccessful reading is distinguished by a non empty value from the `getError()` method.
As a flux query result can contain several tables, differing by grouping key, use the `hasTableChanged()` method to determine when there is a new table.
Single values are returned using the `getValueByIndex()` or `getValueByName()` methods.
All row values at once are retrieved by the `getValues()` method.
Always call the `close()` method at the of reading.
A value in the flux query result column, retrieved by the `getValueByIndex()` or `getValueByName()` methods, is represented by the `FluxValue` object.
It provides getter methods for supported flux types:
| Flux type | Getter | C type |
| ----- | ------ | --- |
| long | getLong() | long |
| unsignedLong | getUnsignedLong() | unsigned long |
| dateTime:RFC3339, dateTime:RFC3339Nano | getDateTime() | [FluxDateTime](src/query/FluxTypes.h#L100) |
| bool | getBool() | bool |
| double | bool | double |
| string, base64binary, duration | getString() | String |
Calling improper type getter will result in a zero (empty) value.
Check for null (missing) value using the `isNull()` method.
Use the `getRawValue()` method for getting the original string form.
// Construct a Flux query
// Query will find RSSI for last 24 hours for each connected WiFi network with this device computed by given selector function
String query = "from(bucket: \"my-bucket\") |> range(start: -24h) |> filter(fn: (r) => r._measurement == \"wifi_status\" and r._field == \"rssi\"";
query += "and r.device == \"ESP32\")";
query += "|> max()";
// Send query to the server and get result
FluxQueryResult result = client.query(query);
// Iterate over rows. Even there is just one row, next() must be called at least once.
while (result.next()) {
// Get typed value for flux result column 'SSID'