{"id":13529379,"url":"https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino","last_synced_at":"2025-04-01T16:31:22.460Z","repository":{"id":37596171,"uuid":"138654012","full_name":"tobiasschuerg/InfluxDB-Client-for-Arduino","owner":"tobiasschuerg","description":"Simple library for sending measurements to an InfluxDB with a single network request. Supports ESP8266 and ESP32.","archived":false,"fork":false,"pushed_at":"2024-09-21T06:10:47.000Z","size":630,"stargazers_count":382,"open_issues_count":16,"forks_count":95,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-11-15T09:48:11.646Z","etag":null,"topics":["arduino-library","esp32","esp8266","esp8266-arduino","influxdb","influxdb-client","measurements"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tobiasschuerg.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-25T21:53:28.000Z","updated_at":"2024-11-13T21:50:31.000Z","dependencies_parsed_at":"2024-01-23T16:10:23.699Z","dependency_job_id":"509f2505-4992-472d-a0e6-c38df20231b4","html_url":"https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobiasschuerg%2FInfluxDB-Client-for-Arduino","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobiasschuerg%2FInfluxDB-Client-for-Arduino/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobiasschuerg%2FInfluxDB-Client-for-Arduino/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobiasschuerg%2FInfluxDB-Client-for-Arduino/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tobiasschuerg","download_url":"https://codeload.github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246670543,"owners_count":20815002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino-library","esp32","esp8266","esp8266-arduino","influxdb","influxdb-client","measurements"],"created_at":"2024-08-01T07:00:35.818Z","updated_at":"2025-04-01T16:31:22.034Z","avatar_url":"https://github.com/tobiasschuerg.png","language":"C++","funding_links":[],"categories":["Client libraries"],"sub_categories":["Unofficial"],"readme":"[![PlatformIO](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/workflows/PlatformIO/badge.svg)](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/actions/)\n\n# InfluxDB Arduino Client\n\nSimple 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.\n\nIt also allows setting data in various formats, automatically escapes special characters and offers specifying timestamp in various precisions.\n\nLibrary supports both [InfluxDB 2](#basic-code-for-influxdb-2) and [InfluxDB 1](#basic-code-for-influxdb-2).\n\nThis is a new implementation and the API, [original API](#original-api) is still supported.\n\nSupported devices: \n - 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).\n - 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). \n\nThis library doesn't support using those devices as a peripheral. \n\n:warning: Only connection over internal WiFi capability is supported for now.\n\n## Table of contents\n- [InfluxDB Arduino Client](#influxdb-arduino-client)\n  - [Basic code for InfluxDB 2](#basic-code-for-influxdb-2)\n  - [Basic code for InfluxDB 1](#basic-code-for-influxdb-1)\n  - [Connecting to InfluxDB Cloud 2](#connecting-to-influxdb-cloud-2)\n  - [Writing in Batches](#writing-in-batches)\n    - [Timestamp](#timestamp)\n    - [Configure Time](#configure-time)\n    - [Batch Size](#batch-size)\n    - [Large Batch Size](#large-batch-size)\n    - [Write Modes](#write-modes)\n  - [Buffer Handling and Retrying](#buffer-handling-and-retrying)\n  - [Write Options](#write-options)\n  - [HTTP Options](#http-options)\n  - [Secure Connection](#secure-connection)\n    - [InfluxDb 2](#influxdb-2)\n    - [InfluxDb 1](#influxdb-1)\n    - [Skipping certificate validation](#skipping-certificate-validation)\n  - [Querying](#querying)\n    - [Parametrized Queries](#parametrized-queries)\n  - [Original API](#original-api)\n    - [Initialization](#initialization)\n    - [Sending a single measurement](#sending-a-single-measurement)\n    - [Write multiple data points at once](#write-multiple-data-points-at-once)\n  - [Troubleshooting](#troubleshooting)\n  - [Contributing](#contributing)\n  - [License](#license)\n\n\n## Basic code for InfluxDB 2\nAfter [setting up an InfluxDB 2 server](https://docs.influxdata.com/influxdb/v2.0/get-started/), first define connection parameters and a client instance:\n```cpp\n// InfluxDB 2 server url, e.g. http://192.168.1.48:8086 (Use: InfluxDB UI -\u003e Load Data -\u003e Client Libraries)\n#define INFLUXDB_URL \"influxdb-url\"\n// InfluxDB 2 server or cloud API authentication token (Use: InfluxDB UI -\u003e Load Data -\u003e Tokens -\u003e \u003cselect token\u003e)\n#define INFLUXDB_TOKEN \"token\"\n// InfluxDB 2 organization name or id (Use: InfluxDB UI -\u003e Settings -\u003e Profile -\u003e \u003cname under tile\u003e )\n#define INFLUXDB_ORG \"org\"\n// InfluxDB 2 bucket name (Use: InfluxDB UI -\u003e Load Data -\u003e Buckets)\n#define INFLUXDB_BUCKET \"bucket\"\n\n// Single InfluxDB instance\nInfluxDBClient client(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN);\n```\n\nThe 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):\n```cpp\n// Define data point in the measurement named 'device_status`\nPoint pointDevice(\"device_status\");\n// Set tags\npointDevice.addTag(\"device\", \"ESP8266\");\npointDevice.addTag(\"SSID\", WiFi.SSID());\n// Add data fields\npointDevice.addField(\"rssi\", WiFi.RSSI());\npointDevice.addField(\"uptime\", millis());\n```\n\nAnd finally, write the data to the database:\n```cpp\n// Write data\nclient.writePoint(pointDevice);\n```\n\nComplete source code is available in the [BasicWrite example](examples/BasicWrite/BasicWrite.ino).\n\nData 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/).\n\n## Basic code for InfluxDB 1\nUsing 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.\nThere is also a different `InfluxDBClient constructor` and  `setConnectionParametersV1` function for setting the security params. Everything else remains the same.\n\n```cpp\n// InfluxDB server url, e.g. http://192.168.1.48:8086 (don't use localhost, always server name or ip address)\n#define INFLUXDB_URL \"influxdb-url\"\n// InfluxDB database name\n#define INFLUXDB_DB_NAME \"database\"\n\n// Single InfluxDB instance\nInfluxDBClient client(INFLUXDB_URL, INFLUXDB_DB_NAME);\n\n// Define data point with measurement name 'device_status`\nPoint pointDevice(\"device_status\");\n// Set tags\npointDevice.addTag(\"device\", \"ESP8266\");\npointDevice.addTag(\"SSID\", WiFi.SSID());\n// Add data\npointDevice.addField(\"rssi\", WiFi.RSSI());\npointDevice.addField(\"uptime\", millis());\n\n// Write data\nclient.writePoint(pointDevice);\n```\n\nComplete source code is available in [BasicWrite example](examples/BasicWrite/BasicWrite.ino)\n\n## Connecting to InfluxDB Cloud 2\nInstead 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).\n\nInfluxDB 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. \n\nConnecting an Arduino client to InfluxDB Cloud server requires a few additional steps comparing to connecting to local server.\n\nConnection 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 -\u003e Load Data -\u003e Client Libraries`.\n```cpp\n//Include also InfluxCloud 2 CA certificate\n#include \u003cInfluxDbCloud.h\u003e\n// InfluxDB 2 server or cloud url, e.g. https://eu-central-1-1.aws.cloud2.influxdata.com (Use: InfluxDB UI -\u003e Load Data -\u003e Client Libraries)\n#define INFLUXDB_URL \"influxdb-url\"\n// InfluxDB 2 server or cloud API authentication token (Use: InfluxDB UI -\u003e Load Data -\u003e Tokens -\u003e \u003cselect token\u003e)\n#define INFLUXDB_TOKEN \"token\"\n// InfluxDB 2 organization name or id (Use: InfluxDB UI -\u003e Settings -\u003e Profile -\u003e \u003cname under tile\u003e )\n#define INFLUXDB_ORG \"org\"\n// InfluxDB 2 bucket name (Use: InfluxDB UI -\u003e Load Data -\u003e Buckets)\n#define INFLUXDB_BUCKET \"bucket\"\n```\n\nYou 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:\n```cpp\n// Single InfluxDB instance\nInfluxDBClient client(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN, InfluxDbCloud2CACert);\n```\nRead more about [secure connection](#secure-connection).\n\nAdditionally, time needs to be synced:\n```cpp\n// Synchronize time with NTP servers and set timezone\n// Accurate time is necessary for certificate validation and writing in batches\n// For the fastest time sync find NTP servers in your area: https://www.pool.ntp.org/zone/\nconfigTzTime(TZ_INFO \"pool.ntp.org\", \"time.nis.gov\");\n```\nRead more about time synchronization in [Configure Time](#configure-time).\n\nDefining data and writing it to the DB is the same as in the case of [BasicWrite](#basic-code):\n```cpp\n// Define data point with measurement name 'device_status`\nPoint pointDevice(\"device_status\");\n// Set tags\npointDevice.addTag(\"device\", \"ESP8266\");\npointDevice.addTag(\"SSID\", WiFi.SSID());\n// Add data\npointDevice.addField(\"rssi\", WiFi.RSSI());\npointDevice.addField(\"uptime\", millis());\n\n// Write data\nclient.writePoint(pointDevice);\n```\nComplete source code is available in [SecureWrite example](examples/SecureWrite/SecureWrite.ino).\n\n## Writing in Batches\nInfluxDB 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.\n\n### Timestamp\nIf 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.\nIf 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).\n\nInfluxDB 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.\n\nThe 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__:\n``` cpp\n// Set write precision to milliseconds. Leave other parameters default.\nclient.setWriteOptions(WriteOptions().writePrecision(WritePrecision::MS));\n```\nWhen 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.\nAutomated assigning of timestamp can be turned off by using `WriteOption::useServerTimestamp(true)`. Client will still specify a timestamp precision for a server.\n\nIf you want to manage timestamp on your own, there are several ways to set the timestamp explicitly.\n- `setTime(WritePrecision writePrecision)` - Sets the timestamp to the actual time in the desired precision. The same precision must set in WriteOptions.\n- `setTime(unsigned long long timestamp)` -  Sets the timestamp to an offset since the epoch. Correct precision must be set InfluxDBClient::setWriteOptions.\n- `setTime(String timestamp)` - Sets the timestamp to an offset since the epoch. Correct precision must be set InfluxDBClient::setWriteOptions.\n\nThe `getTime()` method allows copying the timestamp between points.\n\n\n### Configure Time\nDealing 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:\n```cpp\n// Synchronize time with NTP servers and set timezone\n// Accurate time is necessary for certificate validation and writing in batches\n// For the fastest time sync find NTP servers in your area: https://www.pool.ntp.org/zone/\nconfigTzTime(\"PST8PDT\", \"pool.ntp.org\", \"time.nis.gov\");\n```\nThe `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.\nThe 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.\n\nTimezone 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).\nValues for some timezones:\n- Central Europe: `CET-1CEST,M3.5.0,M10.5.0/3`\n- Eastern: `EST5EDT`\n- Japanese: `JST-9`\n- Pacific Time: `PST8PDT`\n\nThere 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.\nIt's declaration is following:\n```cpp\nconfigTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);\n```\n\nIn the example code it would be:\n```cpp\n// Synchronize time with NTP servers\n// Accurate time is necessary for certificate validation and writing in batches\nconfigTime(3600, 3600, \"pool.ntp.org\", \"time.nis.gov\");\n```\n\nBoth `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.\n\nThere 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.\n`timeSync` has the same signature as `configTzTime` and it is included with the main header file `InfluxDbClient.h`:\n```cpp\n// Synchronize time with NTP servers and waits for competition. Prints waiting progress and final synchronized time to the Serial.\n// Accurate time is necessary for certificate validation and writing points in batch\n// For the fastest time sync find NTP servers in your area: https://www.pool.ntp.org/zone/\nvoid timeSync(const char *tzInfo, const char* ntpServer1, const char* ntpServer2 = nullptr, const char* ntpServer3 = nullptr);\n```\n\n### Batch Size\nSetting batch size depends on data gathering and DB updating strategy.\n\nIf data is written in short periods (seconds), the batch size should be set according to your expected write periods and update frequency requirements.\nFor 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. \n\nIn 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.\n\nTo set the batch size we use `WriteOptions` object and  [setWriteOptions](#write-options) function:\n```cpp\n// Enable lines batching\nclient.setWriteOptions(WriteOptions().batchSize(10));\n```\nWriting the point will add a point to the underlying buffer until the batch size is reached:\n```cpp\n// Write first point to the buffer\n// Buffered write always returns `true`\nclient.writePoint(point1);\n// Write second point to the buffer\nclient.writePoint(point2);\n..\n// Write ninth point to the buffer\nclient.writePoint(point9);\n// Writing tenth point will cause flushing buffer and returns actual write result.\nif(!client.writePoint(point10)) {\n    Serial.print(\"InfluxDB write failed: \");\n    Serial.println(client.getLastErrorMessage());\n}\n```\n\nIn 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.\n\n### Large batch size\nThe maximum batch size depends on the available RAM of the device (~45KB for ESP8266 and ~260KB for ESP32). Larger batch size, \u003e100 for ESP8255, \u003e2000 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)\n\nAlways 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. \n\n:warning: Thoroughly test your app when using large batch files. \n\n### Write Modes\nClient has two modes of writing:\n - Buffer (default)\n - Stream\n\nWriting 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.\nThis is the fastest way to write data but requires some amount of free memory. Thus a big batch size cannot be used.\n\nAnother way of writing is *stream write*. \n```cpp\n  // Enables stream write\n  client.setStreamWrite(true);\n```\nIn 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.\n\n## Buffer Handling and Retrying\nInfluxDB contains an underlying buffer for handling writing in batches and automatic retrying on server back-pressure and connection failure.\n\nIts size is controlled by the `bufferSize` param of [WriteOptions](#write-options) object:\n```cpp\n// Increase buffer to allow caching of failed writes\nclient.setWriteOptions(WriteOptions().bufferSize(50));\n```\nThe recommended size is at least 2 x batch size.\n\nThe state of the buffer can be determined via two functions:\n - `isBufferEmpty()` - Returns true if buffer is empty\n - `isBufferFull()` - Returns true if buffer is full\n\n 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.\n\n 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.\n\nThe `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:\n\n ```cpp\n  // Check whether buffer in not empty\n  if (!client.isBufferEmpty()) {\n      // Write all remaining points to db\n      client.flushBuffer();\n  }\n```\n\nOther functions for dealing with buffer:\n - `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.\n - `resetBuffer()` - Clears the buffer.\n\nCheck [SecureBatchWrite example](examples/SecureBatchWrite/SecureBatchWrite.ino) for example code of buffer handling functions.\n\n## Write Options\nWriting points can be controlled via `WriteOptions`, which is set in the `setWriteOptions` function:\n\n| Parameter | Default Value | Meaning |\n|-----------|---------------|---------|\n| writePrecision | `WritePrecision::NoTime` | Timestamp precision of written data |\n| batchSize | `1` | Number of points that will be written to the database at once |\n| 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 |\n| flushInterval | `60` | Maximum time(in seconds) data will be held in buffer before points are written to the db |\n| retryInterval | `5` | Default retry interval in sec, if not sent by server. Value `0` disables retrying |\n| maxRetryInterval | `300` |  Maximum retry interval in sec |\n| maxRetryAttempts | `3` | Maximum count of retry attempts of failed writes |\n\n## HTTP Options\n`HTTPOptions` controls some aspects of HTTP communication and they are set via `setHTTPOptions` function:\n| Parameter | Default Value | Meaning |\n|-----------|---------------|---------|\n| connectionReuse | `false` | Whether HTTP connection should be kept open after initial communication. Usable for frequent writes/queries. |\n| httpReadTimeout | `5000` | Timeout (ms) for reading server response |\n\n## Secure Connection\nConnecting 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.\n\n:memo: In ESP32 arduino SDK (1.0.4), `WiFiClientSecure` doesn't support fingerprint to validate the server certificate.\n\nThe certificate (in PEM format) or SHA1 fingerprint should be placed in flash memory to save RAM.\nCode 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`.\n\nYou can use a custom server certificate by exporting it, e.g. using a web browser:\n```cpp\n// Server certificate in PEM format, placed in the program (flash) memory to save RAM\nconst char ServerCert[] PROGMEM =  R\"EOF(\n-----BEGIN CERTIFICATE-----\nMIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\nWhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\nZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\nMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\nh77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\nA5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\nT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\nB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\nB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\nKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\nOlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\njh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\nqHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\nrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\nHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\nhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\nubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\nNFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\nORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\nTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\njNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\noyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\nmRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\nemyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n-----END CERTIFICATE-----\n)EOF\";\n\n// Alternatively, use a fingerprint of server certificate to set trust. Works only for ESP8266.\nconst char ServerCert[] PROGMEM = \"cabd2a79a1076a31f21d253635cb039d4329a5e8\";\n```\n\n### InfluxDb 2\nThere are two ways to set the certificate or fingerprint to trust a server:\n - Use full param constructor\n```cpp\n// InfluxDB client instance with preconfigured InfluxCloud certificate\nInfluxDBClient client(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN, ServerCert);\n```\n- Use `setConnectionParams` function:\n```cpp\n// InfluxDB client instance\nInfluxDBClient client;\n\nvoid setup() {\n    // configure client\n    client.setConnectionParams(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN, ServerCert);\n}\n```\n### InfluxDb 1\n\nUse `setConnectionParamsV1` function:\n```cpp\n// InfluxDB client instance\nInfluxDBClient client;\n\nvoid setup() {\n    // configure client\n    client.setConnectionParamsV1(INFLUXDB_URL, INFLUXDB_DATABASE, INFLUXDB_USER, INFLUXDB_PASSWORD, ServerCert);\n}\n```\nAnother important prerequisite to successfully validate a server or CA certificate is to have properly synchronized time. More on this in [Configure Time](#configure-time).\n\n:information_source: Time synchronization is not required for validating server certificate via SHA1 fingerprint.\n\n### Skipping certificate validation\nThe 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.\n\nIf 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.\n\nThe 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. \nYou will also save space in flash (and RAM) by leaving certificate param empty when calling constructor or `setConnectionParams` method.\n\n: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: \n\n```cpp\n// InfluxDB client instance without a server certificate\nInfluxDBClient client(INFLUXDB_URL, INFLUXDB_ORG, INFLUXDB_BUCKET, INFLUXDB_TOKEN);\n\nvoid setup() {\n    // Set insecure connection to skip server certificate validation \n    client.setInsecure();\n}\n```\n\n:warning: Using untrusted connection is a security risk.\n\n## Querying\nInfluxDB 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.\n\nThe `query` returns `FluxQueryResult` object, which parses response and provides useful getters for accessing values from result set.\n\nThe 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:\n```CSV\n#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,string,string,string\n,result,table,_start,_stop,_time,_value,SSID,_field,_measurement,device\n,_result,0,2020-05-18T15:06:00.475253281Z,2020-05-19T15:06:00.475253281Z,2020-05-19T13:07:13Z,-55,667G,rssi,wifi_status,ESP32\n,_result,0,2020-05-18T15:06:00.475253281Z,2020-05-19T15:06:00.475253281Z,2020-05-19T13:07:27Z,-54,667G,rssi,wifi_status,ESP32\n,_result,0,2020-05-18T15:06:00.475253281Z,2020-05-19T15:06:00.475253281Z,2020-05-19T13:07:40Z,-54,667G,rssi,wifi_status,ESP32\n,_result,0,2020-05-18T15:06:00.475253281Z,2020-05-19T15:06:00.475253281Z,2020-05-19T13:07:54Z,-54,667G,rssi,wifi_status,ESP32\n,_result,0,2020-05-18T15:06:00.475253281Z,2020-05-19T15:06:00.475253281Z,2020-05-19T13:08:07Z,-55,667G,rssi,wifi_status,ESP32\n,_result,0,2020-05-18T15:06:00.475253281Z,2020-05-19T15:06:00.475253281Z,2020-05-19T13:08:20Z,-56,667G,rssi,wifi_status,ESP32\n```\n\nAccessing 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\nin the `InfluxDB Data Explorer` and use the final query with this library.\n\n 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.\n 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.\n Single values are returned using the `getValueByIndex()` or `getValueByName()` methods.\n All row values at once are retrieved by the `getValues()` method.\n  Always call the `close()` method at the of reading.\n\nA value in the flux query result column, retrieved by the `getValueByIndex()` or `getValueByName()` methods, is represented by the `FluxValue` object.\nIt provides getter methods for supported flux types:\n\n| Flux type | Getter | C type |\n| ----- | ------ |  --- |\n| long | getLong() | long |\n| unsignedLong | getUnsignedLong() | unsigned long |\n| dateTime:RFC3339, dateTime:RFC3339Nano | getDateTime() |  [FluxDateTime](src/query/FluxTypes.h#L100) |\n| bool | getBool() | bool |\n| double | bool | double |\n| string, base64binary, duration | getString() | String |\n\nCalling improper type getter will result in a zero (empty) value.\n\nCheck for null (missing) value using the `isNull()` method.\n\nUse the `getRawValue()` method for getting the original string form.\n\n```cpp\n// Construct a Flux query\n// Query will find RSSI for last 24 hours for each connected WiFi network with this device computed by given selector function\nString query = \"from(bucket: \\\"my-bucket\\\") |\u003e range(start: -24h) |\u003e filter(fn: (r) =\u003e r._measurement == \\\"wifi_status\\\" and r._field == \\\"rssi\\\"\";\nquery += \"and r.device == \\\"ESP32\\\")\";\nquery += \"|\u003e max()\";\n\n// Send query to the server and get result\nFluxQueryResult result = client.query(query);\n\n// Iterate over rows. Even there is just one row, next() must be called at least once.\nwhile (result.next()) {\n  // Get typed value for flux result column 'SSID'\n  String ssid = result.getValueByName(\"SSID\").getString();\n  Serial.print(\"SSID '\");\n  Serial.print(ssid);\n\n  Serial.print(\"' with RSSI \");\n\n  // Get converted value for flux result column '_value' where there is RSSI value\n  long value = result.getValueByName(\"_value\").getLong();\n  Serial.print(value);\n\n  // Format date-time for printing\n  // Format string according to http://www.cplusplus.com/reference/ctime/strftime/\n  String timeStr = time.format(\"%F %T\");\n\n  Serial.print(\" at \");\n  Serial.print(timeStr);\n\n  Serial.println();\n}\n\n// Check if there was an error\nif(result.getError() != \"\") {\n  Serial.print(\"Query result error: \");\n  Serial.println(result.getError());\n}\n```\nComplete source code is available in [QueryAggregated example](examples/QueryAggregated/QueryAggregated.ino).\n\n### Parametrized Queries\nInfluxDB Cloud supports [Parameterized Queries](https://docs.influxdata.com/influxdb/cloud/query-data/parameterized-queries/)\nthat let you dynamically change values in a query using the InfluxDB API. Parameterized queries make Flux queries more\nreusable and can also be used to help prevent injection attacks.\n\nInfluxDB Cloud inserts the params object into the Flux query as a Flux record named `params`. Use dot or bracket\nnotation to access parameters in the `params` record in your Flux query. Parameterized Flux queries support only `int`\n, `float`, and `string` data types. To convert the supported data types into\nother [Flux basic data types, use Flux type conversion functions](https://docs.influxdata.com/influxdb/cloud/query-data/parameterized-queries/#supported-parameter-data-types).\n\nParameterized query example:\n\u003e :warning: Parameterized Queries are supported only in InfluxDB Cloud. There is no support in InfluxDB OSS currently.\n\n```cpp\n// Prepare query parameters\nQueryParams params;\nparams.add(\"bucket\", INFLUXDB_BUCKET);\nparams.add(\"since\", \"-5m\");\nparams.add(\"device\", DEVICE);\nparams.add(\"rssiThreshold\", -50);\n\n// Construct a Flux query using parameters\n// Parameters are accessed via the 'params' Flux object\n// Flux only supports only string, float and int as parameters. Duration can be converted from string.\n// Query will find RSSI less than defined threshold\nString query = \"from(bucket: params.bucket) |\u003e range(start: duration(v: params.since)) \\\n  |\u003e filter(fn: (r) =\u003e r._measurement == \\\"wifi_status\\\") \\\n  |\u003e filter(fn: (r) =\u003e r._field == \\\"rssi\\\") \\\n  |\u003e filter(fn: (r) =\u003e r.device == params.device) \\\n  |\u003e filter(fn: (r) =\u003e r._value \u003c params.rssiThreshold)\";\n\n// Print ouput header\n// Print composed query\nSerial.print(\"Querying with: \");\nSerial.println(query);\n\n// Send query to the server and get result\nFluxQueryResult result = client.query(query, params);\n\n//Print header\nSerial.printf(\"%10s %20s %5s\\n\",\"Time\",\"SSID\",\"RSSI\");\n\nfor(int i=0;i\u003c37;i++) {\n  Serial.print('-');\n}\nSerial.println();\n\n// Iterate over rows. Even there is just one row, next() must be called at least once.\nint c = 0;\nwhile (result.next()) {\n  // Get converted value for flux result column 'SSID'\n  String ssid = result.getValueByName(\"SSID\").getString();\n  \n  // Get converted value for flux result column '_value' where there is RSSI value\n  long rssi = result.getValueByName(\"_value\").getLong();\n\n  // Get converted value for the _time column\n  FluxDateTime time = result.getValueByName(\"_time\").getDateTime();\n\n  // Format date-time for printing\n  // Format string according to http://www.cplusplus.com/reference/ctime/strftime/\n  String timeStr = time.format(\"%F %T\");\n  // Print formatted row\n  Serial.printf(\"%20s %10s %5d\\n\", timeStr.c_str(), ssid.c_str() ,rssi);\n  c++;\n}\nif(!c) {\n  Serial.println(\" No data found\");\n}\n\n// Check if there was an error\nif(result.getError() != \"\") {\n  Serial.print(\"Query result error: \");\n  Serial.println(result.getError());\n}\n\n// Close the result\nresult.close();\n```\nComplete source code is available in [QueryParams example](examples/QueryParams/QueryParams.ino).\n\n## Original API\n\n### Initialization\n```cpp\n #define INFLUXDB_HOST \"192.168.0.32\"\n #define INFLUXDB_PORT 1337\n #define INFLUXDB_DATABASE \"test\"\n //if used with authentication\n #define INFLUXDB_USER \"user\"\n #define INFLUXDB_PASS \"password\"\n\n // connect to WiFi\n\n Influxdb influx(INFLUXDB_HOST); // port defaults to 8086\n // or to use a custom port\n Influxdb influx(INFLUXDB_HOST, INFLUXDB_PORT);\n\n // set the target database\n influx.setDb(INFLUXDB_DATABASE);\n // or use a db with auth\n influx.setDbAuth(INFLUXDB_DATABASE, INFLUXDB_USER, INFLUXDB_PASS) // with authentication\n\n// To use the v2.0 InfluxDB\ninflux.setVersion(2);\ninflux.setOrg(\"myOrganization\");\ninflux.setBucket(\"myBucket\");\ninflux.setToken(\"myToken\");\ninflux.setPort(8086);\n```\n\n### Sending a single measurement\n**Using an InfluxData object:**\n```cpp\n// create a measurement object\nInfluxData measurement (\"temperature\");\nmeasurement.addTag(\"device\", d2);\nmeasurement.addTag(\"sensor\", \"dht11\");\nmeasurement.addValue(\"value\", 24.0);\n\n// write it into db\ninflux.write(measurement);\n```\n\n**Using raw-data**\n```cpp\n influx.write(\"temperature,device=d2,sensor=dht11 value=24.0\")\n```\n\n### Write multiple data points at once\nBatching measurements and send them with a single request will result in a much higher performance.\n```cpp\n\nInfluxData measurement1 = readTemperature()\ninflux.prepare(measurement1)\n\nInfluxData measurement2 = readLight()\ninflux.prepare(measurement2)\n\nInfluxData measurement3 = readVoltage()\ninflux.prepare(measurement3)\n\n// writes all prepared measurements with a single request into db.\nboolean success = influx.write();\n```\n\n## Troubleshooting\nAll db methods return status. Value `false` means something went wrong. Call `getLastErrorMessage()` to get the error message.\n\nWhen 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:\n```cpp\n// Uncomment bellow in case of a problem and rebuild sketch\n#define INFLUXDB_CLIENT_DEBUG_ENABLE\n```\nThen upload your sketch again and see the debug output in the Serial Monitor.\n\nIf you couldn't solve a problem by yourself, please, post an issue including the debug output.\n\n## Contributing\n\nIf you would like to contribute code you can do through GitHub by forking the repository and sending a pull request into the `master` branch.\n\n## License\n\nThe InfluxDB Arduino Client is released under the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobiasschuerg%2FInfluxDB-Client-for-Arduino","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftobiasschuerg%2FInfluxDB-Client-for-Arduino","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobiasschuerg%2FInfluxDB-Client-for-Arduino/lists"}