Jts/api guides (#3862)
* - Add tutorial that guides a developer through building a simplified IoT
center app with client libraries.
- device registration and authorization.
- write and query--explain batch writes with the JS client library.
* - feat: queries and visualizations with Giraffe library. queryToTable, Giraffe table.
* feat(api-guide): revise intro, auth, example headings.
* feat(api-guide): describe resources. describe auth and API tokens.
- API basics
* fix: influxdb and iot center setup
* fix: update registration steps to include the new INFLUX_BUCKET_AUTH flow.
* feat(api-guides): Add client library example to fetch routes.
- install, links.
- replace use of getIoTAuthorizations with query from getDevices.
- breakdown create device API requests.
- initial commit of API guide using Next.js with Influx client libraries. Project source at https://github.com/jstirnaman/nextjs-iot-starter.
- explain the flow to register a device. Remove unused example code. TODO: document the setup and UI.
- Add UI code samples. Revise headings. Explain API purpose.
- UI component fixes and refactor. Input field takes a device ID, queries, and re-renders the list with results. Registration button submits device ID for a new authorization.
* feat(api-guide): add iot-starter guide index page, fix errors
- add the iot-starter directory and index page
- fix tag errors and links.
* feat: IoT starter navigation.
* feat(api-guide): nav and intros.
* wip: rearrange, move full examples to top of section and link to explainers.
* chore: Shared intro shortcode for iot-starter tutorials.
* fix: intros, navigation, and config instruction
- Add intro shortcode for tutorials to share.
- Organize navigation for language-specific tutorials (would prefer to unify as much as possible).
- Update environment variable config instruction.
* Feature/api guide python client (#4023)
* adding placeholders into code
* create_device not tested yet
* everything working except flux query and filter query
* fix: replace download button with spec link. (#4013)
- Closes #3810 - Remove download button and add a link to the spec source in Github.
* Enterprise 1.9.7 release notes (#4007)
* added not under flux updates
* updates based on feedback
* changed release notes date
* added requested update
* added detail about script builder (#3995)
* added detail about script builder
* Update content/chronograf/v1.9/guides/querying-data.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* fix: async writes and deletes (#4015)
- Correct handling of writes and deletes in cloud vs. oss (async vs. sync).
- Cleanup redundancy in Troubleshooting.
- Closes https://github.com/influxdata/DAR/issues/291
Co-authored-by: lwandzura <51929958+lwandzura@users.noreply.github.com>
* Collect user feedback per page and restructure modals (#4014)
* WIP feedback forms
* WIP complete feedback lifecycles
* finalize page feedback interactions
Co-authored-by: kelseiv <47797004+kelseiv@users.noreply.github.com>
* Revert "Enterprise 1.9.7 release notes (#4007)" (#4017)
This reverts commit c6f4a99d72
.
* hotfix: fix cli homebrew package name, closes #4022
* docs: add python iot guide
* fix: remove .idea files
* fix: remove .idea files and package-lock
* fix: initial batch of fixes
* fix: finished PR changes
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
* Update content/influxdb/v2.2/api-guide/iot-starter/_index.md
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Update content/influxdb/v2.2/api-guide/iot-starter/python.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Update content/influxdb/v2.2/api-guide/iot-starter/_index.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Update content/influxdb/v2.2/api-guide/iot-starter/_index.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Update content/influxdb/v2.2/api-guide/iot-starter/_index.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Delete _index.md
Co-authored-by: Sunbrye Ly <sunbryely@Sunbryes-MacBook-Pro.local>
Co-authored-by: Jason Stirnaman <jstirnaman@influxdata.com>
Co-authored-by: lwandzura <51929958+lwandzura@users.noreply.github.com>
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
Co-authored-by: kelseiv <47797004+kelseiv@users.noreply.github.com>
Co-authored-by: Scott Anderson <scott@influxdata.com>
Co-authored-by: Sunbrye Ly <sunbryely@Sunbryes-MBP.lan>
* chore: replace UI code with GH links, fix navigation.
* feat: API client library tutorials
- Cleanup py and js tutorials.
- JS is still WIP.
- Fix nav.
* fix: Revise Node.js tutorial.
* fix: Revise Python tutorial.
* fix: Remove last bullet since Node.js tutorial isn't that far yet.
* Update content/influxdb/v2.2/api-guide/tutorials/client-library-starter/_index.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* Update content/influxdb/v2.2/api-guide/tutorials/client-library-starter/nodejs.md
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
* wip: Install and run the UI.
* docs: fix instructions and move UI docs to iot-api-ui README.
* fix: Update JS and Py tutorials with common UI.
* fix: Update code samples in nodejs and python IoT starter tutorials.
* fix: fixup.
* fix: Cleanup code tabs.
* fix: update toc
* fix: iot-starter
Fix examples.
Cleanup.
* fix: python restart
* fix: Cleanup.
* chore: add repo links
* Add cloud, fix frontmatter.
* fix: Remove links to sections.
Co-authored-by: sunbryely-influxdata <101659702+sunbryely-influxdata@users.noreply.github.com>
Co-authored-by: Sunbrye Ly <sunbryely@Sunbryes-MacBook-Pro.local>
Co-authored-by: lwandzura <51929958+lwandzura@users.noreply.github.com>
Co-authored-by: Scott Anderson <sanderson@users.noreply.github.com>
Co-authored-by: kelseiv <47797004+kelseiv@users.noreply.github.com>
Co-authored-by: Scott Anderson <scott@influxdata.com>
Co-authored-by: Sunbrye Ly <sunbryely@Sunbryes-MBP.lan>
pull/4130/head
parent
bb10438c0b
commit
9e33fe690a
|
@ -9,3 +9,5 @@ node_modules
|
||||||
/content/influxdb/*/api/*.html
|
/content/influxdb/*/api/*.html
|
||||||
/api-docs/redoc-static.html*
|
/api-docs/redoc-static.html*
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
.idea
|
||||||
|
package-lock.json
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: InfluxDB API client library tutorials
|
||||||
|
seotitle: Get started with InfluxDB API client libraries
|
||||||
|
description: Follow step-by-step tutorials to for InfluxDB API client libraries in your favorite framework or language.
|
||||||
|
weight: 4
|
||||||
|
menu:
|
||||||
|
influxdb_cloud:
|
||||||
|
name: Client library tutorials
|
||||||
|
parent: Develop with the API
|
||||||
|
influxdb/cloud/tags: [api]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{< children >}}
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: InfluxDB API client library starter
|
||||||
|
seotitle: Starter tutorial for InfluxDB API client libraries
|
||||||
|
description: Follow step-by-step tutorials to build an IoT dashboard with API client libraries in your favorite framework or language.
|
||||||
|
weight: 4
|
||||||
|
menu:
|
||||||
|
influxdb_cloud:
|
||||||
|
name: Client library starter
|
||||||
|
parent: Client library tutorials
|
||||||
|
influxdb/cloud/tags: [api]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% duplicate-oss %}}
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
title: JavaScript client library starter
|
||||||
|
seotitle: Use JavaScript client library to build a sample application
|
||||||
|
list_title: JavaScript client library starter
|
||||||
|
description: >
|
||||||
|
Build a JavaScript application that writes, queries, and manages devices with the
|
||||||
|
InfluxDB client library.
|
||||||
|
menu:
|
||||||
|
influxdb_cloud:
|
||||||
|
identifier: client-library-starter-js
|
||||||
|
name: JavaScript
|
||||||
|
parent: Client library starter
|
||||||
|
influxdb/cloud/tags: [api, javascript, nodejs]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% duplicate-oss %}}
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
title: Python client library starter
|
||||||
|
seotitle: Use Python client library to build a sample application
|
||||||
|
list_title: Python
|
||||||
|
description: >
|
||||||
|
Build an application that writes, queries, and manages devices with the InfluxDB
|
||||||
|
client library for Python.
|
||||||
|
weight: 3
|
||||||
|
menu:
|
||||||
|
influxdb_cloud:
|
||||||
|
identifier: client-library-starter-py
|
||||||
|
name: Python
|
||||||
|
parent: Client library starter
|
||||||
|
influxdb/cloud/tags: [api, python]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% duplicate-oss %}}
|
|
@ -12,20 +12,28 @@ influxdb/v2.2/tags: [api]
|
||||||
The InfluxDB v2 API provides a programmatic interface for interactions with InfluxDB.
|
The InfluxDB v2 API provides a programmatic interface for interactions with InfluxDB.
|
||||||
Access the InfluxDB API using the `/api/v2/` endpoint.
|
Access the InfluxDB API using the `/api/v2/` endpoint.
|
||||||
|
|
||||||
|
## Developer guides
|
||||||
|
|
||||||
|
- [API starter guide](/influxdb/v2.2/api-guide/starter/)
|
||||||
|
|
||||||
## InfluxDB client libraries
|
## InfluxDB client libraries
|
||||||
|
|
||||||
InfluxDB client libraries are language-specific packages that integrate with the InfluxDB v2 API.
|
InfluxDB client libraries are language-specific packages that integrate with the InfluxDB v2 API.
|
||||||
For information about supported client libraries, see [InfluxDB client libraries](/{{< latest "influxdb" >}}/api-guide/client-libraries/).
|
For tutorials and information about client libraries, see [InfluxDB client libraries](/{{< latest "influxdb" >}}/api-guide/client-libraries/).
|
||||||
|
|
||||||
## InfluxDB v2 API documentation
|
## InfluxDB v2 API documentation
|
||||||
|
|
||||||
<a class="btn" href="/influxdb/v2.2/api/">InfluxDB OSS {{< current-version >}} API documentation</a>
|
<a class="btn" href="/influxdb/v2.2/api/">InfluxDB OSS {{< current-version >}} API documentation</a>
|
||||||
|
|
||||||
#### View InfluxDB API documentation locally
|
### View InfluxDB API documentation locally
|
||||||
|
|
||||||
InfluxDB API documentation is built into the `influxd` service and represents
|
InfluxDB API documentation is built into the `influxd` service and represents
|
||||||
the API specific to the current version of InfluxDB.
|
the API specific to the current version of InfluxDB.
|
||||||
To view the API documentation locally, [start InfluxDB](/influxdb/v2.2/get-started/#start-influxdb)
|
To view the API documentation locally, [start InfluxDB](/influxdb/v2.2/get-started/#start-influxdb)
|
||||||
and visit the `/docs` endpoint in a browser ([localhost:8086/docs](http://localhost:8086/docs)).
|
and visit the `/docs` endpoint in a browser ([localhost:8086/docs](http://localhost:8086/docs)).
|
||||||
|
|
||||||
## InfluxDB v1 compatibility API documentation
|
## InfluxDB v1 compatibility API documentation
|
||||||
|
|
||||||
The InfluxDB v2 API includes [InfluxDB 1.x compatibility endpoints](/influxdb/v2.2/reference/api/influxdb-1x/)
|
The InfluxDB v2 API includes [InfluxDB 1.x compatibility endpoints](/influxdb/v2.2/reference/api/influxdb-1x/)
|
||||||
that work with InfluxDB 1.x client libraries and third-party integrations like
|
that work with InfluxDB 1.x client libraries and third-party integrations like
|
||||||
[Grafana](https://grafana.com) and others.
|
[Grafana](https://grafana.com) and others.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
title: API Quick Start
|
title: API Quick Start
|
||||||
seotitle: Use the InfluxDB API
|
seotitle: Use the InfluxDB API
|
||||||
description: Interact with InfluxDB 1 using a rich API for writing and querying data and more.
|
description: Interact with InfluxDB using a rich API for writing and querying data and more.
|
||||||
weight: 3
|
weight: 3
|
||||||
menu:
|
menu:
|
||||||
influxdb_2_2:
|
influxdb_2_2:
|
||||||
name: Quick Start
|
name: Quick start
|
||||||
parent: Develop with the API
|
parent: Develop with the API
|
||||||
aliases:
|
aliases:
|
||||||
- /influxdb/v2.2/tools/api/
|
- /influxdb/v2.2/tools/api/
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
title: InfluxDB API client library tutorials
|
||||||
|
seotitle: Get started with InfluxDB API client libraries
|
||||||
|
description: Follow step-by-step tutorials to for InfluxDB API client libraries in your favorite framework or language.
|
||||||
|
weight: 4
|
||||||
|
menu:
|
||||||
|
influxdb_2_2:
|
||||||
|
name: Client library tutorials
|
||||||
|
parent: Develop with the API
|
||||||
|
influxdb/v2.2/tags: [api]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{< children >}}
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
title: InfluxDB API client library starter
|
||||||
|
seotitle: Starter tutorial for InfluxDB API client libraries
|
||||||
|
description: Follow step-by-step tutorials to build an IoT dashboard with API client libraries in your favorite framework or language.
|
||||||
|
weight: 4
|
||||||
|
menu:
|
||||||
|
influxdb_2_2:
|
||||||
|
name: Client library starter
|
||||||
|
parent: Client library tutorials
|
||||||
|
influxdb/v2.2/tags: [api]
|
||||||
|
---
|
||||||
|
|
||||||
|
Follow step-by-step tutorials to build an Internet-of-Things (IoT) application with InfluxData client libraries and your favorite framework or language.
|
||||||
|
InfluxData and the user community maintain client libraries for developers who want to take advantage of:
|
||||||
|
|
||||||
|
- Idioms for InfluxDB requests, responses, and errors.
|
||||||
|
- Common patterns in a familiar programming language.
|
||||||
|
- Faster development and less boilerplate code.
|
||||||
|
|
||||||
|
These tutorials walk through using the InfluxDB API and
|
||||||
|
client libraries to build a modern application as you learn the following:
|
||||||
|
|
||||||
|
- InfluxDB core concepts.
|
||||||
|
- How the application interacts with devices and InfluxDB.
|
||||||
|
- How to authenticate apps and devices to the API.
|
||||||
|
- How to install a client library.
|
||||||
|
- How to write and query data in InfluxDB.
|
||||||
|
- How to use the InfluxData UI libraries to format data and create visualizations.
|
||||||
|
|
||||||
|
{{< children >}}
|
|
@ -0,0 +1,508 @@
|
||||||
|
---
|
||||||
|
title: JavaScript client library starter
|
||||||
|
seotitle: Use JavaScript client library to build a sample application
|
||||||
|
list_title: JavaScript client library starter
|
||||||
|
description: >
|
||||||
|
Build a JavaScript application that writes, queries, and manages devices with the
|
||||||
|
InfluxDB client library.
|
||||||
|
menu:
|
||||||
|
influxdb_2_2:
|
||||||
|
identifier: client-library-starter-js
|
||||||
|
name: JavaScript
|
||||||
|
parent: Client library starter
|
||||||
|
influxdb/v2.2/tags: [api, javascript, nodejs]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% api/iot-starter-intro %}}
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- [Contents](#contents)
|
||||||
|
- [Set up InfluxDB](#set-up-influxdb)
|
||||||
|
- [Authenticate with an InfluxDB API token](#authenticate-with-an-influxdb-api-token)
|
||||||
|
- [Introducing IoT Starter](#introducing-iot-starter)
|
||||||
|
- [Create the application](#create-the-application)
|
||||||
|
- [Install InfluxDB client library](#install-influxdb-client-library)
|
||||||
|
- [Configure the client library](#configure-the-client-library)
|
||||||
|
- [Build the API](#build-the-api)
|
||||||
|
- [Create the API to list devices](#create-the-api-to-list-devices)
|
||||||
|
- [Handle requests for device information](#handle-requests-for-device-information)
|
||||||
|
- [Retrieve and list devices](#retrieve-and-list-devices)
|
||||||
|
- [Create the API to register devices](#create-the-api-to-register-devices)
|
||||||
|
- [Create an authorization for the device](#create-an-authorization-for-the-device)
|
||||||
|
- [Write the device authorization to a bucket](#write-the-device-authorization-to-a-bucket)
|
||||||
|
- [Install and run the UI](#install-and-run-the-ui)
|
||||||
|
|
||||||
|
## Set up InfluxDB
|
||||||
|
|
||||||
|
If you haven't already, [create an InfluxDB Cloud account](https://www.influxdata.com/products/influxdb-cloud/) or [install InfluxDB OSS](https://www.influxdata.com/products/influxdb/).
|
||||||
|
|
||||||
|
### Authenticate with an InfluxDB API token
|
||||||
|
|
||||||
|
For convenience in development,
|
||||||
|
[create an _All-Access_ token](/influxdb/v2.2/security/tokens/create-token/)
|
||||||
|
for your application. This grants your application full read and write
|
||||||
|
permissions on all resources within your InfluxDB organization.
|
||||||
|
|
||||||
|
{{% note %}}
|
||||||
|
|
||||||
|
For a production application, create and use a
|
||||||
|
{{% cloud-only %}}custom{{% /cloud-only %}}{{% oss-only %}}read-write{{% /oss-only %}}
|
||||||
|
token with minimal permissions and only use it with your application.
|
||||||
|
|
||||||
|
{{% /note %}}
|
||||||
|
|
||||||
|
## Introducing IoT Starter
|
||||||
|
|
||||||
|
The application architecture has four layers:
|
||||||
|
|
||||||
|
- **InfluxDB API**: InfluxDB v2 API.
|
||||||
|
- **IoT device**: Virtual or physical devices write IoT data to the InfluxDB API.
|
||||||
|
- **UI**: Sends requests to the server and renders views in the browser.
|
||||||
|
- **API**: Receives requests from the UI, sends requests to InfluxDB, and processes responses from InfluxDB.
|
||||||
|
|
||||||
|
{{% note %}}
|
||||||
|
For the complete code referenced in this tutorial, see the [influxdata/iot-api-js repository](https://github.com/influxdata/iot-api-js).
|
||||||
|
{{% /note %}}
|
||||||
|
|
||||||
|
## Create the application
|
||||||
|
|
||||||
|
Create a directory that will contain your `iot-api` projects.
|
||||||
|
The following example code creates an `iot-api` directory in your home directory
|
||||||
|
and changes to the new directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir ~/iot-api-apps
|
||||||
|
cd ~/iot-api-apps
|
||||||
|
```
|
||||||
|
|
||||||
|
Use [Next.js](https://nextjs.org/), a framework for full-stack JavaScript applications, to create your application.
|
||||||
|
|
||||||
|
1. In your `~/iot-api-apps` directory, open a terminal and enter the following commands to create the `iot-api-js` app from the NextJS [learn-starter template](https://github.com/vercel/next-learn/tree/master/basics/learn-starter):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-next-app iot-api-js --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. After the installation completes, enter the following commands in your terminal to go into your `./iot-api-js` directory and start the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd iot-api-js
|
||||||
|
npm run dev -p 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
To view the application, visit <http://localhost:3001> in your browser.
|
||||||
|
|
||||||
|
## Install InfluxDB client library
|
||||||
|
|
||||||
|
The InfluxDB client library provides the following InfluxDB API interactions:
|
||||||
|
|
||||||
|
- Query data with the Flux language.
|
||||||
|
- Write data to InfluxDB.
|
||||||
|
- Batch data in the background.
|
||||||
|
- Retry requests automatically on failure.
|
||||||
|
|
||||||
|
1. Enter the following command into your terminal to install the client library:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i @influxdata/influxdb-client
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Enter the following command into your terminal to install `@influxdata/influxdb-client-apis`, the _management APIs_ that create, modify, and delete authorizations, buckets, tasks, and other InfluxDB resources:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i @influxdata/influxdb-client-apis
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information about the client library, see the [influxdata/influxdb-client-js repo](https://github.com/influxdata/influxdb-client-js).
|
||||||
|
|
||||||
|
## Configure the client library
|
||||||
|
|
||||||
|
InfluxDB client libraries require configuration properties from your InfluxDB environment.
|
||||||
|
Typically, you'll provide the following properties as environment variables for your application:
|
||||||
|
|
||||||
|
- `INFLUX_URL`
|
||||||
|
- `INFLUX_TOKEN`
|
||||||
|
- `INFLUX_ORG`
|
||||||
|
- `INFLUX_BUCKET`
|
||||||
|
- `INFLUX_BUCKET_AUTH`
|
||||||
|
|
||||||
|
Next.js uses the `env` module to provide environment variables to your application.
|
||||||
|
|
||||||
|
The `./.env.development` file is versioned and contains non-secret default settings for your _development_ environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env.development
|
||||||
|
|
||||||
|
INFLUX_URL=http://localhost:8086
|
||||||
|
INFLUX_BUCKET=iot_center
|
||||||
|
INFLUX_BUCKET_AUTH=iot_center_devices
|
||||||
|
```
|
||||||
|
|
||||||
|
To configure secrets and settings that aren't added to version control,
|
||||||
|
create a `./.env.local` file and set the variables--for example, set your InfluxDB token and organization:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# .env.local
|
||||||
|
|
||||||
|
# INFLUX_TOKEN
|
||||||
|
# InfluxDB API token used by the application server to send requests to InfluxDB.
|
||||||
|
# For convenience in development, use an **All-Access** token.
|
||||||
|
|
||||||
|
INFLUX_TOKEN=29Xx1KH9VkASPR2DSfRfFd82OwGD...
|
||||||
|
|
||||||
|
# INFLUX_ORG
|
||||||
|
# InfluxDB organization ID you want to use in development.
|
||||||
|
|
||||||
|
INFLUX_ORG=48c88459ee424a04
|
||||||
|
```
|
||||||
|
|
||||||
|
Enter the following commands into your terminal to restart and load the `.env` files:
|
||||||
|
|
||||||
|
1. `CONTROL+C` to stop the application.
|
||||||
|
2. `npm run dev` to start the application.
|
||||||
|
|
||||||
|
Next.js sets variables that you can access in the `process.env` object--for example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
console.log(process.env.INFLUX_ORG)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build the API
|
||||||
|
|
||||||
|
Your application API provides server-side HTTP endpoints that process requests from the UI.
|
||||||
|
Each API endpoint is responsible for the following:
|
||||||
|
|
||||||
|
1. Listen for HTTP requests (from the UI).
|
||||||
|
2. Translate requests into InfluxDB API requests.
|
||||||
|
3. Process InfluxDB API responses and handle errors.
|
||||||
|
4. Respond with status and data (for the UI).
|
||||||
|
|
||||||
|
## Create the API to list devices
|
||||||
|
|
||||||
|
Add the `/api/devices` API endpoint that retrieves, processes, and lists devices.
|
||||||
|
`/api/devices` uses the `/api/v2/query` InfluxDB API endpoint to query `INFLUX_BUCKET_AUTH` for a registered device.
|
||||||
|
|
||||||
|
### Handle requests for device information
|
||||||
|
|
||||||
|
1. Create a `./pages/api/devices/[[...deviceParams]].js` file to handle requests for `/api/devices` and `/api/devices/<deviceId>/measurements/`.
|
||||||
|
|
||||||
|
2. In the file, export a Next.js request `handler` function.
|
||||||
|
[See the example](https://github.com/influxdata/iot-api-js/blob/18d34bcd59b93ad545c5cd9311164c77f6d1995a/pages/api/devices/%5B%5B...deviceParams%5D%5D.js).
|
||||||
|
|
||||||
|
{{% note %}}
|
||||||
|
In Next.js, the filename pattern `[[...param]].js` creates a _catch-all_ API route.
|
||||||
|
To learn more, see [Next.js dynamic API routes](https://nextjs.org/docs/api-routes/dynamic-api-routes).
|
||||||
|
{{% /note %}}
|
||||||
|
|
||||||
|
### Retrieve and list devices
|
||||||
|
|
||||||
|
Retrieve registered devices in `INFLUX_BUCKET_AUTH` and process the query results.
|
||||||
|
|
||||||
|
1. Create a Flux query that gets the last row of each [series](/influxdb/v2.2/reference/glossary#series) that contains a `deviceauth` measurement.
|
||||||
|
The example query below returns rows that contain the `key` field (authorization ID) and excludes rows that contain a `token` field (to avoid exposing tokens to the UI).
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Flux query finds devices
|
||||||
|
from(bucket:`${INFLUX_BUCKET_AUTH}`)
|
||||||
|
|> range(start: 0)
|
||||||
|
|> filter(fn: (r) => r._measurement == "deviceauth" and r._field != "token")
|
||||||
|
|> last()
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Use the `QueryApi` client to send the Flux query to the `POST /api/v2/query` InfluxDB API endpoint.
|
||||||
|
|
||||||
|
Create a `./pages/api/devices/_devices.js` file that contains the following:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Node.js](#nodejs)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
{{% truncate %}}
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { InfluxDB } from '@influxdata/influxdb-client'
|
||||||
|
import { flux } from '@influxdata/influxdb-client'
|
||||||
|
|
||||||
|
const INFLUX_ORG = process.env.INFLUX_ORG
|
||||||
|
const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
|
||||||
|
const influxdb = new InfluxDB({url: process.env.INFLUX_URL, token: process.env.INFLUX_TOKEN})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets devices or a particular device when deviceId is specified. Tokens
|
||||||
|
* are not returned unless deviceId is specified. It can also return devices
|
||||||
|
* with empty/unknown key, such devices can be ignored (InfluxDB authorization is not associated).
|
||||||
|
* @param deviceId optional deviceId
|
||||||
|
* @returns promise with an Record<deviceId, {deviceId, createdAt, updatedAt, key, token}>.
|
||||||
|
*/
|
||||||
|
export async function getDevices(deviceId) {
|
||||||
|
const queryApi = influxdb.getQueryApi(INFLUX_ORG)
|
||||||
|
const deviceFilter =
|
||||||
|
deviceId !== undefined
|
||||||
|
? flux` and r.deviceId == "${deviceId}"`
|
||||||
|
: flux` and r._field != "token"`
|
||||||
|
const fluxQuery = flux`from(bucket:${INFLUX_BUCKET_AUTH})
|
||||||
|
|> range(start: 0)
|
||||||
|
|> filter(fn: (r) => r._measurement == "deviceauth"${deviceFilter})
|
||||||
|
|> last()`
|
||||||
|
const devices = {}
|
||||||
|
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
queryApi.queryRows(fluxQuery, {
|
||||||
|
next(row, tableMeta) {
|
||||||
|
const o = tableMeta.toObject(row)
|
||||||
|
const deviceId = o.deviceId
|
||||||
|
if (!deviceId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const device = devices[deviceId] || (devices[deviceId] = {deviceId})
|
||||||
|
device[o._field] = o._value
|
||||||
|
if (!device.updatedAt || device.updatedAt < o._time) {
|
||||||
|
device.updatedAt = o._time
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: reject,
|
||||||
|
complete() {
|
||||||
|
resolve(devices)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% /truncate %}}
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-js/pages/api/devices/_devices.js getDevices(deviceId)](https://github.com/influxdata/iot-api-js/blob/18d34bcd59b93ad545c5cd9311164c77f6d1995a/pages/api/devices/_devices.js){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
The `_devices` module exports a `getDevices(deviceId)` function that queries
|
||||||
|
for registered devices, processes the data, and returns a Promise with the result.
|
||||||
|
If you invoke the function as `getDevices()` (without a _`deviceId`_),
|
||||||
|
it retrieves all `deviceauth` points and returns a Promise with `{ DEVICE_ID: ROW_DATA }`.
|
||||||
|
|
||||||
|
To send the query and process results, the `getDevices(deviceId)` function uses the `QueryAPI queryRows(query, consumer)` method.
|
||||||
|
`queryRows` executes the `query` and provides the Annotated CSV result as an Observable to the `consumer`.
|
||||||
|
`queryRows` has the following TypeScript signature:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
queryRows(
|
||||||
|
query: string | ParameterizedQuery,
|
||||||
|
consumer: FluxResultObserver<string[]>
|
||||||
|
): void
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[@influxdata/influxdb-client-js QueryAPI](https://github.com/influxdata/influxdb-client-js/blob/3db2942432b993048d152e0d0e8ec8499eedfa60/packages/core/src/QueryApi.ts){{% /caption %}}
|
||||||
|
|
||||||
|
The `consumer` that you provide must implement the [`FluxResultObserver` interface](https://github.com/influxdata/influxdb-client-js/blob/3db2942432b993048d152e0d0e8ec8499eedfa60/packages/core/src/results/FluxResultObserver.ts) and provide the following callback functions:
|
||||||
|
|
||||||
|
- `next(row, tableMeta)`: processes the next row and table metadata--for example, to prepare the response.
|
||||||
|
- `error(error)`: receives and handles errors--for example, by rejecting the Promise.
|
||||||
|
- `complete()`: signals when all rows have been consumed--for example, by resolving the Promise.
|
||||||
|
|
||||||
|
To learn more about Observers, see the [RxJS Guide](https://rxjs.dev/guide/observer).
|
||||||
|
|
||||||
|
## Create the API to register devices
|
||||||
|
|
||||||
|
In this application, a _registered device_ is a point that contains your device ID, authorization ID, and API token.
|
||||||
|
The API token and authorization permissions allow the device to query and write to `INFLUX_BUCKET`.
|
||||||
|
In this section, you add the API endpoint that handles requests from the UI, creates an authorization in InfluxDB,
|
||||||
|
and writes the registered device to the `INFLUX_BUCKET_AUTH` bucket.
|
||||||
|
To learn more about API tokens and authorizations, see [Manage API tokens](/influxdb/v2.2/security/tokens/)
|
||||||
|
|
||||||
|
The application API uses the following `/api/v2` InfluxDB API endpoints:
|
||||||
|
|
||||||
|
- `POST /api/v2/query`: to query `INFLUX_BUCKET_AUTH` for a registered device.
|
||||||
|
- `GET /api/v2/buckets`: to get the bucket ID for `INFLUX_BUCKET`.
|
||||||
|
- `POST /api/v2/authorizations`: to create an authorization for the device.
|
||||||
|
- `POST /api/v2/write`: to write the device authorization to `INFLUX_BUCKET_AUTH`.
|
||||||
|
|
||||||
|
1. Add a `./pages/api/devices/create.js` file to handle requests for `/api/devices/create`.
|
||||||
|
2. In the file, export a Next.js request `handler` function that does the following:
|
||||||
|
|
||||||
|
1. Accept a device ID in the request body.
|
||||||
|
2. Query `INFLUX_BUCKET_AUTH` and respond with an error if an authorization exists for the device.
|
||||||
|
3. [Create an authorization for the device](#create-an-authorization-for-the-device).
|
||||||
|
4. [Write the device ID and authorization to `INFLUX_BUCKET_AUTH`](#write-the-device-authorization-to-a-bucket).
|
||||||
|
5. Respond with `HTTP 200` when the write request completes.
|
||||||
|
|
||||||
|
[See the example](https://github.com/influxdata/iot-api-js/blob/25b38c94a1f04ea71f2ef4b9fcba5350d691cb9d/pages/api/devices/create.js).
|
||||||
|
|
||||||
|
### Create an authorization for the device
|
||||||
|
|
||||||
|
In this section, you create an authorization with _read_-_write_ permission to `INFLUX_BUCKET` and receive an API token for the device.
|
||||||
|
The example below uses the following steps to create the authorization:
|
||||||
|
|
||||||
|
1. Instantiate the `AuthorizationsAPI` client and `BucketsAPI` client with the configuration.
|
||||||
|
2. Retrieve the bucket ID.
|
||||||
|
3. Use the client library to send a `POST` request to the `/api/v2/authorizations` InfluxDB API endpoint.
|
||||||
|
|
||||||
|
In `./api/devices/create.js`, add the following `createAuthorization(deviceId)` function:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Node.js](#nodejs)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
{{% truncate %}}
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { InfluxDB } from '@influxdata/influxdb-client'
|
||||||
|
import { getDevices } from './_devices'
|
||||||
|
import { AuthorizationsAPI, BucketsAPI } from '@influxdata/influxdb-client-apis'
|
||||||
|
import { Point } from '@influxdata/influxdb-client'
|
||||||
|
|
||||||
|
const INFLUX_ORG = process.env.INFLUX_ORG
|
||||||
|
const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
|
||||||
|
const INFLUX_BUCKET = process.env.INFLUX_BUCKET
|
||||||
|
|
||||||
|
const influxdb = new InfluxDB({url: process.env.INFLUX_URL, token: process.env.INFLUX_TOKEN})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an authorization for a supplied deviceId
|
||||||
|
* @param {string} deviceId client identifier
|
||||||
|
* @returns {import('@influxdata/influxdb-client-apis').Authorization} promise with authorization or an error
|
||||||
|
*/
|
||||||
|
async function createAuthorization(deviceId) {
|
||||||
|
const authorizationsAPI = new AuthorizationsAPI(influxdb)
|
||||||
|
const bucketsAPI = new BucketsAPI(influxdb)
|
||||||
|
const DESC_PREFIX = 'IoTCenterDevice: '
|
||||||
|
|
||||||
|
const buckets = await bucketsAPI.getBuckets({name: INFLUX_BUCKET, orgID: INFLUX_ORG})
|
||||||
|
const bucketId = buckets.buckets[0]?.id
|
||||||
|
|
||||||
|
return await authorizationsAPI.postAuthorizations({
|
||||||
|
body: {
|
||||||
|
orgID: INFLUX_ORG,
|
||||||
|
description: DESC_PREFIX + deviceId,
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
action: 'read',
|
||||||
|
resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'write',
|
||||||
|
resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% /truncate %}}
|
||||||
|
{{% caption %}}[iot-api-js/pages/api/devices/create.js](https://github.com/influxdata/iot-api-js/blob/42a37d683b5e4df601422f85d2c22f5e9d592e68/pages/api/devices/create.js){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
To create an authorization that has _read_-_write_ permission to `INFLUX_BUCKET`, you need the bucket ID.
|
||||||
|
To retrieve the bucket ID,
|
||||||
|
`createAuthorization(deviceId)` calls the `BucketsAPI getBuckets` function that sends a `GET` request to
|
||||||
|
the `/api/v2/buckets` InfluxDB API endpoint.
|
||||||
|
`createAuthorization(deviceId)` then passes a new authorization in the request body with the following:
|
||||||
|
|
||||||
|
- Bucket ID.
|
||||||
|
- Organization ID.
|
||||||
|
- Description: `IoTCenterDevice: DEVICE_ID`.
|
||||||
|
- List of permissions to the bucket.
|
||||||
|
|
||||||
|
To learn more about API tokens and authorizations, see [Manage API tokens](/influxdb/v2.2/security/tokens/).
|
||||||
|
|
||||||
|
Next, [write the device authorization to a bucket](#write-the-device-authorization-to-a-bucket).
|
||||||
|
|
||||||
|
### Write the device authorization to a bucket
|
||||||
|
|
||||||
|
With a device authorization in InfluxDB, write a point for the device and authorization details to `INFLUX_BUCKET_AUTH`.
|
||||||
|
Storing the device authorization in a bucket allows you to do the following:
|
||||||
|
|
||||||
|
- Report device authorization history.
|
||||||
|
- Manage devices with and without tokens.
|
||||||
|
- Assign the same token to multiple devices.
|
||||||
|
- Refresh tokens.
|
||||||
|
|
||||||
|
To write a point to InfluxDB, use the InfluxDB client library to send a `POST` request to the `/api/v2/write` InfluxDB API endpoint.
|
||||||
|
In `./pages/api/devices/create.js`, add the following `createDevice(deviceId)` function:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Node.js](#nodejs)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
```ts
|
||||||
|
/** Creates an authorization for a deviceId and writes it to a bucket */
|
||||||
|
async function createDevice(deviceId) {
|
||||||
|
let device = (await getDevices(deviceId)) || {}
|
||||||
|
let authorizationValid = !!Object.values(device)[0]?.key
|
||||||
|
if(authorizationValid) {
|
||||||
|
console.log(JSON.stringify(device))
|
||||||
|
return Promise.reject('This device ID is already registered and has an authorization.')
|
||||||
|
} else {
|
||||||
|
console.log(`createDeviceAuthorization: deviceId=${deviceId}`)
|
||||||
|
const authorization = await createAuthorization(deviceId)
|
||||||
|
const writeApi = influxdb.getWriteApi(INFLUX_ORG, INFLUX_BUCKET_AUTH, 'ms', {
|
||||||
|
batchSize: 2,
|
||||||
|
})
|
||||||
|
const point = new Point('deviceauth')
|
||||||
|
.tag('deviceId', deviceId)
|
||||||
|
.stringField('key', authorization.id)
|
||||||
|
.stringField('token', authorization.token)
|
||||||
|
writeApi.writePoint(point)
|
||||||
|
await writeApi.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-js/pages/api/devices/create.js](https://github.com/influxdata/iot-api-js/blob/25b38c94a1f04ea71f2ef4b9fcba5350d691cb9d/pages/api/devices/create.js){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
`createDevice(device_id)` takes a _`device_id`_ and writes data to `INFLUX_BUCKET_AUTH` in the following steps:
|
||||||
|
|
||||||
|
1. Initialize `InfluxDBClient()` with `url`, `token`, and `org` values from the configuration.
|
||||||
|
2. Initialize a `WriteAPI` client for writing data to an InfluxDB bucket.
|
||||||
|
3. Create a `Point`.
|
||||||
|
4. Use `writeApi.writePoint(point)` to write the `Point` to the bucket.
|
||||||
|
|
||||||
|
The function writes a point with the following elements:
|
||||||
|
|
||||||
|
| Element | Name | Value |
|
||||||
|
|:------------|:-----------|:--------------------------|
|
||||||
|
| measurement | | `deviceauth` |
|
||||||
|
| tag | `deviceId` | device ID |
|
||||||
|
| field | `key` | authorization ID |
|
||||||
|
| field | `token` | authorization (API) token |
|
||||||
|
|
||||||
|
## Install and run the UI
|
||||||
|
|
||||||
|
`influxdata/iot-api-ui` is a standalone [Next.js React](https://nextjs.org/docs/basic-features/pages) UI that uses your application API to write and query data in InfluxDB.
|
||||||
|
`iot-api-ui` uses Next.js _[rewrites](https://nextjs.org/docs/api-reference/next.config.js/rewrites)_ to route all requests in the `/api/` path to your API.
|
||||||
|
|
||||||
|
To install and run the UI, do the following:
|
||||||
|
|
||||||
|
1. In your `~/iot-api-apps` directory, clone the [`influxdata/iot-api-ui` repo](https://github.com/influxdata/iot-api-ui) and go into the `iot-api-ui` directory--for example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/iot-api-apps
|
||||||
|
git clone git@github.com:influxdata/iot-api-ui.git
|
||||||
|
cd ./iot-app-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
2. The `./.env.development` file contains default configuration settings that you can
|
||||||
|
edit or override (with a `./.env.local` file).
|
||||||
|
3. To start the UI, enter the following command into your terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
To view the list and register devices, visit <http://localhost:3000/devices> in your browser.
|
||||||
|
|
||||||
|
To learn more about the UI components, see [`influxdata/iot-api-ui`](https://github.com/influxdata/iot-api-ui).
|
|
@ -0,0 +1,583 @@
|
||||||
|
---
|
||||||
|
title: Python client library starter
|
||||||
|
seotitle: Use Python client library to build a sample application
|
||||||
|
list_title: Python
|
||||||
|
description: >
|
||||||
|
Build an application that writes, queries, and manages devices with the InfluxDB
|
||||||
|
client library for Python.
|
||||||
|
weight: 3
|
||||||
|
menu:
|
||||||
|
influxdb_2_2:
|
||||||
|
identifier: client-library-starter-py
|
||||||
|
name: Python
|
||||||
|
parent: Client library starter
|
||||||
|
influxdb/v2.2/tags: [api, python]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{% api/iot-starter-intro %}}
|
||||||
|
- How to use the InfluxData UI libraries to format data and create visualizations.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- [Contents](#contents)
|
||||||
|
- [Set up InfluxDB](#set-up-influxdb)
|
||||||
|
- [Authenticate with an InfluxDB API token](#authenticate-with-an-influxdb-api-token)
|
||||||
|
- [Introducing IoT Starter](#introducing-iot-starter)
|
||||||
|
- [Create the application](#create-the-application)
|
||||||
|
- [Install InfluxDB client library](#install-influxdb-client-library)
|
||||||
|
- [Configure the client library](#configure-the-client-library)
|
||||||
|
- [Build the API](#build-the-api)
|
||||||
|
- [Create the API to register devices](#create-the-api-to-register-devices)
|
||||||
|
- [Create an authorization for the device](#create-an-authorization-for-the-device)
|
||||||
|
- [Write the device authorization to a bucket](#write-the-device-authorization-to-a-bucket)
|
||||||
|
- [Create the API to list devices](#create-the-api-to-list-devices)
|
||||||
|
- [Create IoT virtual device](#create-iot-virtual-device)
|
||||||
|
- [Write telemetry data](#write-telemetry-data)
|
||||||
|
- [Query telemetry data](#query-telemetry-data)
|
||||||
|
- [Define API responses](#define-api-responses)
|
||||||
|
- [Install and run the UI](#install-and-run-the-ui)
|
||||||
|
|
||||||
|
## Set up InfluxDB
|
||||||
|
|
||||||
|
If you haven't already, [create an InfluxDB Cloud account](https://www.influxdata.com/products/influxdb-cloud/) or [install InfluxDB OSS](https://www.influxdata.com/products/influxdb/).
|
||||||
|
|
||||||
|
### Authenticate with an InfluxDB API token
|
||||||
|
|
||||||
|
For convenience in development,
|
||||||
|
[create an _All-Access_ token](/influxdb/v2.2/security/tokens/create-token/)
|
||||||
|
for your application. This grants your application full read and write
|
||||||
|
permissions on all resources within your InfluxDB organization.
|
||||||
|
|
||||||
|
{{% note %}}
|
||||||
|
|
||||||
|
For a production application, create and use a
|
||||||
|
{{% cloud-only %}}custom{{% /cloud-only %}}{{% oss-only %}}read-write{{% /oss-only %}}
|
||||||
|
token with minimal permissions and only use it with your application.
|
||||||
|
|
||||||
|
{{% /note %}}
|
||||||
|
|
||||||
|
## Introducing IoT Starter
|
||||||
|
|
||||||
|
The application architecture has four layers:
|
||||||
|
|
||||||
|
- **InfluxDB API**: InfluxDB v2 API.
|
||||||
|
- **IoT device**: Virtual or physical devices write IoT data to the InfluxDB API.
|
||||||
|
- **UI**: Sends requests to the server and renders views in the browser.
|
||||||
|
- **API**: Receives requests from the UI, sends requests to InfluxDB,
|
||||||
|
and processes responses from InfluxDB.
|
||||||
|
|
||||||
|
{{% note %}}
|
||||||
|
For the complete code referenced in this tutorial, see the [influxdata/iot-api-python repository](https://github.com/influxdata/iot-api-python).
|
||||||
|
{{% /note %}}
|
||||||
|
|
||||||
|
## Create the application
|
||||||
|
|
||||||
|
Create a directory that will contain your `iot-api` projects.
|
||||||
|
The following example code creates an `iot-api` directory in your home directory
|
||||||
|
and changes to the new directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir ~/iot-api-apps
|
||||||
|
cd ~/iot-api-apps
|
||||||
|
```
|
||||||
|
|
||||||
|
Use [Flask](https://flask.palletsprojects.com/), a lightweight Python web
|
||||||
|
framework,
|
||||||
|
to create your application.
|
||||||
|
|
||||||
|
1. In your `~/iot-api-apps` directory, open a terminal and enter the following commands to create and navigate into a new project directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir iot-api-python && cd $_
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Enter the following commands in your terminal to create and activate a Python virtual environment for the project:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a new virtual environment named "virtualenv"
|
||||||
|
# Python 3.8+
|
||||||
|
python -m venv virtualenv
|
||||||
|
|
||||||
|
# Activate the virtualenv (OS X & Linux)
|
||||||
|
source virtualenv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
3. After activation completes, enter the following commands in your terminal to install Flask with the `pip` package installer (included with Python):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install Flask
|
||||||
|
```
|
||||||
|
|
||||||
|
4. In your project, create a `app.py` file that:
|
||||||
|
|
||||||
|
1. Imports the Flask package.
|
||||||
|
2. Instantiates a Flask application.
|
||||||
|
3. Provides a route to execute the application.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello():
|
||||||
|
return "Hello World!"
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[influxdata/iot-api-python app.py](https://github.com/influxdata/iot-api-python/blob/main/app.py){{% /caption %}}
|
||||||
|
|
||||||
|
Start your application.
|
||||||
|
The following example code starts the application
|
||||||
|
on `http://localhost:3001` with debugging and hot-reloading enabled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export FLASK_ENV=development
|
||||||
|
flask run -h localhost -p 3001
|
||||||
|
```
|
||||||
|
|
||||||
|
In your browser, visit <http://localhost:3001> to view the “Hello World!” response.
|
||||||
|
|
||||||
|
## Install InfluxDB client library
|
||||||
|
|
||||||
|
The InfluxDB client library provides the following InfluxDB API interactions:
|
||||||
|
|
||||||
|
- Query data with the Flux language.
|
||||||
|
- Write data to InfluxDB.
|
||||||
|
- Batch data in the background.
|
||||||
|
- Retry requests automatically on failure.
|
||||||
|
|
||||||
|
Enter the following command into your terminal to install the client library:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install influxdb-client
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information about the client library, see the [influxdata/influxdb-client-python repo](https://github.com/influxdata/influxdb-client-python).
|
||||||
|
|
||||||
|
## Configure the client library
|
||||||
|
|
||||||
|
InfluxDB client libraries require configuration properties from your InfluxDB environment.
|
||||||
|
Typically, you'll provide the following properties as environment variables for your application:
|
||||||
|
|
||||||
|
- `INFLUX_URL`
|
||||||
|
- `INFLUX_TOKEN`
|
||||||
|
- `INFLUX_ORG`
|
||||||
|
- `INFLUX_BUCKET`
|
||||||
|
- `INFLUX_BUCKET_AUTH`
|
||||||
|
|
||||||
|
To set up the client configuration, create a `config.ini` in your project's top
|
||||||
|
level directory and paste the following to provide the necessary InfluxDB credentials:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[APP]
|
||||||
|
INFLUX_URL = <INFLUX_URL>
|
||||||
|
INFLUX_TOKEN = <INFLUX_TOKEN>
|
||||||
|
INFLUX_ORG = <INFLUX_ORG_ID>
|
||||||
|
INFLUX_BUCKET = iot_center
|
||||||
|
INFLUX_BUCKET_AUTH = iot_center_devices
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[/iot-api-python/config.ini](https://github.com/influxdata/iot-api-python/blob/main/config.ini){{% /caption %}}
|
||||||
|
|
||||||
|
Replace the following:
|
||||||
|
|
||||||
|
- **`<INFLUX_URL>`**: your InfluxDB instance URL.
|
||||||
|
- **`<INFLUX_TOKEN>`**: your InfluxDB [API token](#authorization) with permission to query (_read_) buckets
|
||||||
|
and create (_write_) authorizations for devices.
|
||||||
|
- **`<INFLUX_ORG_ID>`**: your InfluxDB organization ID.
|
||||||
|
|
||||||
|
## Build the API
|
||||||
|
|
||||||
|
Your application API provides server-side HTTP endpoints that process requests from the UI.
|
||||||
|
Each API endpoint is responsible for the following:
|
||||||
|
|
||||||
|
1. Listen for HTTP requests (from the UI).
|
||||||
|
2. Translate requests into InfluxDB API requests.
|
||||||
|
3. Process InfluxDB API responses and handle errors.
|
||||||
|
4. Respond with status and data (for the UI).
|
||||||
|
|
||||||
|
## Create the API to register devices
|
||||||
|
|
||||||
|
In this application, a _registered device_ is a point that contains your device ID, authorization ID, and API token.
|
||||||
|
The API token and authorization permissions allow the device to query and write to `INFLUX_BUCKET`.
|
||||||
|
In this section, you add the API endpoint that handles requests from the UI, creates an authorization in InfluxDB,
|
||||||
|
and writes the registered device to the `INFLUX_BUCKET_AUTH` bucket.
|
||||||
|
To learn more about API tokens and authorizations, see [Manage API tokens](/influxdb/v2.2/security/tokens/)
|
||||||
|
|
||||||
|
The application API uses the following `/api/v2` InfluxDB API endpoints:
|
||||||
|
|
||||||
|
- `POST /api/v2/query`: to query `INFLUX_BUCKET_AUTH` for a registered device.
|
||||||
|
- `GET /api/v2/buckets`: to get the bucket ID for `INFLUX_BUCKET`.
|
||||||
|
- `POST /api/v2/authorizations`: to create an authorization for the device.
|
||||||
|
- `POST /api/v2/write`: to write the device authorization to `INFLUX_BUCKET_AUTH`.
|
||||||
|
|
||||||
|
### Create an authorization for the device
|
||||||
|
|
||||||
|
In this section, you create an authorization with _read_-_write_ permission to `INFLUX_BUCKET` and receive an API token for the device.
|
||||||
|
The example below uses the following steps to create the authorization:
|
||||||
|
|
||||||
|
1. Instantiate the `AuthorizationsAPI` client and `BucketsAPI` client with the configuration.
|
||||||
|
2. Retrieve the bucket ID.
|
||||||
|
3. Use the client library to send a `POST` request to the `/api/v2/authorizations` InfluxDB API endpoint.
|
||||||
|
|
||||||
|
Create a `./api/devices.py` file that contains the following:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Python](#python)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
{{% truncate %}}
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Import the dependencies.
|
||||||
|
import configparser
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
# Import client library classes.
|
||||||
|
from influxdb_client import Authorization, InfluxDBClient, Permission, PermissionResource, Point, WriteOptions
|
||||||
|
from influxdb_client.client.authorizations_api import AuthorizationsApi
|
||||||
|
from influxdb_client.client.bucket_api import BucketsApi
|
||||||
|
from influxdb_client.client.query_api import QueryApi
|
||||||
|
from influxdb_client.client.write_api import SYNCHRONOUS
|
||||||
|
|
||||||
|
from api.sensor import Sensor
|
||||||
|
|
||||||
|
# Get the configuration key-value pairs.
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read('config.ini')
|
||||||
|
|
||||||
|
def create_authorization(device_id) -> Authorization:
|
||||||
|
influxdb_client = InfluxDBClient(url=config.get('APP', 'INFLUX_URL'),
|
||||||
|
token=os.environ.get('INFLUX_TOKEN'),
|
||||||
|
org=os.environ.get('INFLUX_ORG'))
|
||||||
|
|
||||||
|
authorization_api = AuthorizationsApi(influxdb_client)
|
||||||
|
# get bucket_id from bucket
|
||||||
|
buckets_api = BucketsApi(influxdb_client)
|
||||||
|
buckets = buckets_api.find_bucket_by_name(config.get('APP', 'INFLUX_BUCKET')) # function returns only 1 bucket
|
||||||
|
bucket_id = buckets.id
|
||||||
|
org_id = buckets.org_id
|
||||||
|
desc_prefix = f'IoTCenterDevice: {device_id}'
|
||||||
|
org_resource = PermissionResource(org_id=org_id, id=bucket_id, type="buckets")
|
||||||
|
read = Permission(action="read", resource=org_resource)
|
||||||
|
write = Permission(action="write", resource=org_resource)
|
||||||
|
permissions = [read, write]
|
||||||
|
authorization = Authorization(org_id=org_id, permissions=permissions, description=desc_prefix)
|
||||||
|
request = authorization_api.create_authorization(authorization)
|
||||||
|
return request
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% /truncate %}}
|
||||||
|
{{% caption %}}[iot-api-python/api/devices.py](https://github.com/influxdata/iot-api-python/blob/d389a0e072c7a03dfea99e5663bdc32be94966bb/api/devices.py#L145){{% /caption %}}
|
||||||
|
|
||||||
|
To create an authorization that has _read_-_write_ permission to `INFLUX_BUCKET`, you need the bucket ID.
|
||||||
|
To retrieve the bucket ID, `create_authorization(deviceId)` calls the
|
||||||
|
`BucketsAPI find_bucket_by_name` function that sends a `GET` request to
|
||||||
|
the `/api/v2/buckets` InfluxDB API endpoint.
|
||||||
|
`create_authorization(deviceId)` then passes a new authorization in the request body with the following:
|
||||||
|
|
||||||
|
- Bucket ID.
|
||||||
|
- Organization ID.
|
||||||
|
- Description: `IoTCenterDevice: DEVICE_ID`.
|
||||||
|
- List of permissions to the bucket.
|
||||||
|
|
||||||
|
To learn more about API tokens and authorizations, see [Manage API tokens](/influxdb/v2.2/security/tokens/).
|
||||||
|
|
||||||
|
Next, [write the device authorization to a bucket](#write-the-device-authorization-to-a-bucket).
|
||||||
|
|
||||||
|
### Write the device authorization to a bucket
|
||||||
|
|
||||||
|
With a device authorization in InfluxDB, write a point for the device and authorization details to `INFLUX_BUCKET_AUTH`.
|
||||||
|
Storing the device authorization in a bucket allows you to do the following:
|
||||||
|
|
||||||
|
- Report device authorization history.
|
||||||
|
- Manage devices with and without tokens.
|
||||||
|
- Assign the same token to multiple devices.
|
||||||
|
- Refresh tokens.
|
||||||
|
|
||||||
|
To write a point to InfluxDB, use the InfluxDB client library to send a `POST` request to the `/api/v2/write` InfluxDB API endpoint.
|
||||||
|
In `./api/devices.py`, add the following `create_device(device_id)` function:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Python](#python)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
```python
|
||||||
|
def create_device(device_id=None):
|
||||||
|
influxdb_client = InfluxDBClient(url=config.get('APP', 'INFLUX_URL'),
|
||||||
|
token=config.get('APP', 'INFLUX_TOKEN'),
|
||||||
|
org=config.get('APP', 'INFLUX_ORG'))
|
||||||
|
if device_id is None:
|
||||||
|
device_id = str(uuid4())
|
||||||
|
write_api = influxdb_client.write_api(write_options=SYNCHRONOUS)
|
||||||
|
point = Point('deviceauth') \
|
||||||
|
.tag("deviceId", device_id) \
|
||||||
|
.field('key', f'fake_auth_id_{device_id}') \
|
||||||
|
.field('token', f'fake_auth_token_{device_id}')
|
||||||
|
client_response = write_api.write(bucket=config.get('APP', 'INFLUX_BUCKET_AUTH'), record=point)
|
||||||
|
# write() returns None on success
|
||||||
|
if client_response is None:
|
||||||
|
return device_id
|
||||||
|
# Return None on failure
|
||||||
|
return None
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-python/api/devices.py](https://github.com/influxdata/iot-api-python/blob/f354941c80b6bac643ca29efe408fde1deebdc96/api/devices.py#L47){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
`create_device(device_id)` takes a _`device_id`_ and writes data to `INFLUX_BUCKET_AUTH` in the following steps:
|
||||||
|
|
||||||
|
1. Initialize `InfluxDBClient()` with `url`, `token`, and `org` values from the configuration.
|
||||||
|
2. Initialize a `WriteAPI` client for writing data to an InfluxDB bucket.
|
||||||
|
3. Create a `Point`.
|
||||||
|
4. Use `write_api.write()` to write the `Point` to the bucket.
|
||||||
|
5. Check for failures--if the write was successful, `write_api` returns `None`.
|
||||||
|
6. Return _`device_id`_ if successful; `None` otherwise.
|
||||||
|
|
||||||
|
The function writes a point with the following elements:
|
||||||
|
|
||||||
|
| Element | Name | Value |
|
||||||
|
|:------------|:-----------|:--------------------------|
|
||||||
|
| measurement | | `deviceauth` |
|
||||||
|
| tag | `deviceId` | device ID |
|
||||||
|
| field | `key` | authorization ID |
|
||||||
|
| field | `token` | authorization (API) token |
|
||||||
|
|
||||||
|
Next, [create the API to list devices](#create-the-api-to-list-devices).
|
||||||
|
|
||||||
|
## Create the API to list devices
|
||||||
|
|
||||||
|
Add the `/api/devices` API endpoint that retrieves, processes, and lists registered devices.
|
||||||
|
|
||||||
|
1. Create a Flux query that gets the last row of each [series](/influxdb/v2.2/reference/glossary#series) that contains a `deviceauth` measurement.
|
||||||
|
The example query below returns rows that contain the `key` field (authorization ID) and excludes rows that contain a `token` field (to avoid exposing tokens to the UI).
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Flux query finds devices
|
||||||
|
from(bucket:`${INFLUX_BUCKET_AUTH}`)
|
||||||
|
|> range(start: 0)
|
||||||
|
|> filter(fn: (r) => r._measurement == "deviceauth" and r._field != "token")
|
||||||
|
|> last()
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Use the `QueryApi` client to send the Flux query to the `POST /api/v2/query` InfluxDB API endpoint.
|
||||||
|
|
||||||
|
In `./api/devices.py`, add the following:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Python](#python)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
{{% truncate %}}
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_device(device_id=None) -> {}:
|
||||||
|
influxdb_client = InfluxDBClient(url=config.get('APP', 'INFLUX_URL'),
|
||||||
|
token=os.environ.get('INFLUX_TOKEN'),
|
||||||
|
org=os.environ.get('INFLUX_ORG'))
|
||||||
|
# Queries must be formatted with single and double quotes correctly
|
||||||
|
query_api = QueryApi(influxdb_client)
|
||||||
|
device_filter = ''
|
||||||
|
if device_id:
|
||||||
|
device_id = str(device_id)
|
||||||
|
device_filter = f'r.deviceId == "{device_id}" and r._field != "token"'
|
||||||
|
else:
|
||||||
|
device_filter = f'r._field != "token"'
|
||||||
|
|
||||||
|
flux_query = f'from(bucket: "{config.get("APP", "INFLUX_BUCKET_AUTH")}") ' \
|
||||||
|
f'|> range(start: 0) ' \
|
||||||
|
f'|> filter(fn: (r) => r._measurement == "deviceauth" and {device_filter}) ' \
|
||||||
|
f'|> last()'
|
||||||
|
|
||||||
|
response = query_api.query(flux_query)
|
||||||
|
result = []
|
||||||
|
for table in response:
|
||||||
|
for record in table.records:
|
||||||
|
try:
|
||||||
|
'updatedAt' in record
|
||||||
|
except KeyError:
|
||||||
|
record['updatedAt'] = record.get_time()
|
||||||
|
record[record.get_field()] = record.get_value()
|
||||||
|
result.append(record.values)
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% /truncate %}}
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-python/api/devices.py get_device()](https://github.com/influxdata/iot-api-python/blob/9bf44a659424a27eb937d545dc0455754354aef5/api/devices.py#L30){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
The `get_device(device_id)` function does the following:
|
||||||
|
|
||||||
|
1. Instantiates a `QueryApi` client and sends the Flux query to InfluxDB.
|
||||||
|
2. Iterates over the `FluxTable` in the response and returns a list of tuples.
|
||||||
|
|
||||||
|
## Create IoT virtual device
|
||||||
|
|
||||||
|
Create a `./api/sensor.py` file that generates simulated weather telemetry data.
|
||||||
|
Follow the [example code](https://github.com/influxdata/iot-api-python/blob/f354941c80b6bac643ca29efe408fde1deebdc96/api/sensor.py) to create the IoT virtual device.
|
||||||
|
|
||||||
|
Next, generate data for virtual devices and [write the data to InfluxDB](#write-telemetry-data).
|
||||||
|
|
||||||
|
## Write telemetry data
|
||||||
|
|
||||||
|
In this section, you write telemetry data to an InfluxDB bucket.
|
||||||
|
To write data, use the InfluxDB client library to send a `POST` request to the `/api/v2/write` InfluxDB API endpoint.
|
||||||
|
|
||||||
|
The example below uses the following steps to generate data and then write it to InfluxDB:
|
||||||
|
|
||||||
|
1. Initialize a `WriteAPI` instance.
|
||||||
|
2. Create a `Point` with the `environment` measurement and data fields for temperature, humidity, pressure, latitude, and longitude.
|
||||||
|
3. Use the `WriteAPI write` method to send the point to InfluxDB.
|
||||||
|
|
||||||
|
In `./api/devices.py`, add the following `write_measurements(device_id)` function:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Python](#python)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
```python
|
||||||
|
def write_measurements(device_id):
|
||||||
|
influxdb_client = InfluxDBClient(url=config.get('APP', 'INFLUX_URL'),
|
||||||
|
token=config.get('APP', 'INFLUX_TOKEN'),
|
||||||
|
org=config.get('APP', 'INFLUX_ORG'))
|
||||||
|
write_api = influxdb_client.write_api(write_options=SYNCHRONOUS)
|
||||||
|
virtual_device = Sensor()
|
||||||
|
coord = virtual_device.geo()
|
||||||
|
point = Point("environment") \
|
||||||
|
.tag("device", device_id) \
|
||||||
|
.tag("TemperatureSensor", "virtual_bme280") \
|
||||||
|
.tag("HumiditySensor", "virtual_bme280") \
|
||||||
|
.tag("PressureSensor", "virtual_bme280") \
|
||||||
|
.field("Temperature", virtual_device.generate_measurement()) \
|
||||||
|
.field("Humidity", virtual_device.generate_measurement()) \
|
||||||
|
.field("Pressure", virtual_device.generate_measurement()) \
|
||||||
|
.field("Lat", coord['latitude']) \
|
||||||
|
.field("Lon", coord['latitude']) \
|
||||||
|
.time(datetime.utcnow())
|
||||||
|
print(f"Writing: {point.to_line_protocol()}")
|
||||||
|
client_response = write_api.write(bucket=config.get('APP', 'INFLUX_BUCKET'), record=point)
|
||||||
|
# write() returns None on success
|
||||||
|
if client_response is None:
|
||||||
|
# TODO Maybe also return the data that was written
|
||||||
|
return device_id
|
||||||
|
# Return None on failure
|
||||||
|
return None
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-python/api/devices.py write_measurement()](https://github.com/influxdata/iot-api-python/blob/f354941c80b6bac643ca29efe408fde1deebdc96/api/devices.py){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
## Query telemetry data
|
||||||
|
|
||||||
|
In this section, you retrieve telemetry data from an InfluxDB bucket.
|
||||||
|
To retrieve data, use the InfluxDB client library to send a `POST` request to the `/api/v2/query` InfluxDB API endpoint.
|
||||||
|
The example below uses the following steps to retrieve and process telemetry data:
|
||||||
|
|
||||||
|
1. Query `environment` measurements in `INFLUX_BUCKET`.
|
||||||
|
2. Filter results by `device_id`.
|
||||||
|
3. Return CSV data that the [`influxdata/giraffe` UI library](https://github.com/influxdata/giraffe) can process.
|
||||||
|
|
||||||
|
In `./api/devices.py`, add the following `get_measurements(device_id)` function:
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Python](#python)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_measurements(query):
|
||||||
|
influxdb_client = InfluxDBClient(url=config.get('APP', 'INFLUX_URL'),
|
||||||
|
token=os.environ.get('INFLUX_TOKEN'), org=os.environ.get('INFLUX_ORG'))
|
||||||
|
query_api = QueryApi(influxdb_client)
|
||||||
|
result = query_api.query_csv(query,
|
||||||
|
dialect=Dialect(
|
||||||
|
header=True,
|
||||||
|
delimiter=",",
|
||||||
|
comment_prefix="#",
|
||||||
|
annotations=['group', 'datatype', 'default'],
|
||||||
|
date_time_format="RFC3339"))
|
||||||
|
response = ''
|
||||||
|
for row in result:
|
||||||
|
response += (',').join(row) + ('\n')
|
||||||
|
return response
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-python/api/devices.py get_measurements()](https://github.com/influxdata/iot-api-python/blob/9bf44a659424a27eb937d545dc0455754354aef5/api/devices.py#L122){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
## Define API responses
|
||||||
|
|
||||||
|
In `app.py`, add API endpoints that match incoming requests and respond with the results of your modules.
|
||||||
|
In the following `/api/devices/<device_id>` route example, `app.py` retrieves _`device_id`_ from `GET` and `POST` requests, passes it to the `get_device(device_id)` method and returns the result as JSON data with CORS `allow-` headers.
|
||||||
|
|
||||||
|
{{< code-tabs-wrapper >}}
|
||||||
|
{{% code-tabs %}}
|
||||||
|
[Python](#python)
|
||||||
|
{{% /code-tabs %}}
|
||||||
|
{{% code-tab-content %}}
|
||||||
|
|
||||||
|
```python
|
||||||
|
@app.route('/api/devices/<string:device_id>', methods=['GET', 'POST'])
|
||||||
|
def api_get_device(device_id):
|
||||||
|
if request.method == "OPTIONS": # CORS preflight
|
||||||
|
return _build_cors_preflight_response()
|
||||||
|
return _corsify_actual_response(jsonify(devices.get_device(device_id)))
|
||||||
|
```
|
||||||
|
|
||||||
|
{{% caption %}}[iot-api-python/app.py](https://github.com/influxdata/iot-api-python/blob/9bf44a659424a27eb937d545dc0455754354aef5/app.py){{% /caption %}}
|
||||||
|
|
||||||
|
{{% /code-tab-content %}}
|
||||||
|
{{< /code-tabs-wrapper >}}
|
||||||
|
|
||||||
|
Enter the following commands into your terminal to restart the application:
|
||||||
|
|
||||||
|
1. `CONTROL+C` to stop the application.
|
||||||
|
2. `flask run -h localhost -p 3001` to start the application.
|
||||||
|
|
||||||
|
To retrieve devices data from your API, visit <http://localhost:3001/api/devices> in your browser.
|
||||||
|
|
||||||
|
## Install and run the UI
|
||||||
|
|
||||||
|
`influxdata/iot-api-ui` is a standalone [Next.js React](https://nextjs.org/docs/basic-features/pages) UI that uses your application API to write and query data in InfluxDB.
|
||||||
|
`iot-api-ui` uses Next.js _[rewrites](https://nextjs.org/docs/api-reference/next.config.js/rewrites)_ to route all requests in the `/api/` path to your API.
|
||||||
|
|
||||||
|
To install and run the UI, do the following:
|
||||||
|
|
||||||
|
1. In your `~/iot-api-apps` directory, clone the [`influxdata/iot-api-ui` repo](https://github.com/influxdata/iot-api-ui) and go into the `iot-api-ui` directory--for example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/iot-api-apps
|
||||||
|
git clone git@github.com:influxdata/iot-api-ui.git
|
||||||
|
cd ./iot-app-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
2. The `./.env.development` file contains default configuration settings that you can
|
||||||
|
edit or override (with a `./.env.local` file).
|
||||||
|
3. To start the UI, enter the following command into your terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
To view the list and register devices, visit <http://localhost:3000/devices> in your browser.
|
||||||
|
|
||||||
|
To learn more about the UI components, see [`influxdata/iot-api-ui`](https://github.com/influxdata/iot-api-ui).
|
|
@ -0,0 +1,10 @@
|
||||||
|
Follow this step-by-step tutorial to build an Internet-of-Things (IoT) application with InfluxData client libraries and your favorite framework or language.
|
||||||
|
|
||||||
|
In this tutorial, you'll use the InfluxDB API and
|
||||||
|
client libraries to build a modern application as you learn the following:
|
||||||
|
|
||||||
|
- InfluxDB core concepts.
|
||||||
|
- How the application interacts with devices and InfluxDB.
|
||||||
|
- How to authenticate apps and devices to the API.
|
||||||
|
- How to install a client library.
|
||||||
|
- How to write and query data in InfluxDB.
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { flux } from '@influxdata/influxdb-client'
|
||||||
|
import influxdb from '../_influxdb'
|
||||||
|
|
||||||
|
const INFLUX_ORG = process.env.INFLUX_ORG
|
||||||
|
const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets devices or a particular device when deviceId is specified. Tokens
|
||||||
|
* are not returned unless deviceId is specified. It can also return devices
|
||||||
|
* with empty/unknown key, such devices can be ignored (InfluxDB authorization is not associated).
|
||||||
|
* @param deviceId optional deviceId
|
||||||
|
* @returns promise with an Record<deviceId, {deviceId, createdAt, updatedAt, key, token}>.
|
||||||
|
*/
|
||||||
|
export async function getDevices(deviceId) {
|
||||||
|
const queryApi = influxdb.getQueryApi(INFLUX_ORG)
|
||||||
|
const deviceFilter =
|
||||||
|
deviceId !== undefined
|
||||||
|
? flux` and r.deviceId == "${deviceId}"`
|
||||||
|
: flux` and r._field != "token"`
|
||||||
|
const fluxQuery = flux`from(bucket:${INFLUX_BUCKET_AUTH})
|
||||||
|
|> range(start: 0)
|
||||||
|
|> filter(fn: (r) => r._measurement == "deviceauth"${deviceFilter})
|
||||||
|
|> last()`
|
||||||
|
const devices = {}
|
||||||
|
console.log(`*** QUERY *** \n ${fluxQuery}`)
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
queryApi.queryRows(fluxQuery, {
|
||||||
|
next(row, tableMeta) {
|
||||||
|
const o = tableMeta.toObject(row)
|
||||||
|
const deviceId = o.deviceId
|
||||||
|
if (!deviceId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const device = devices[deviceId] || (devices[deviceId] = {deviceId})
|
||||||
|
device[o._field] = o._value
|
||||||
|
if (!device.updatedAt || device.updatedAt < o._time) {
|
||||||
|
device.updatedAt = o._time
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: reject,
|
||||||
|
complete() {
|
||||||
|
console.log(JSON.stringify(devices))
|
||||||
|
resolve(devices)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { getDevices } from './devices/_devices'
|
||||||
|
|
||||||
|
import influxdb from '../_influxdb'
|
||||||
|
import { AuthorizationsAPI, BucketsAPI } from '@influxdata/influxdb-client-apis'
|
||||||
|
import { Point } from '@influxdata/influxdb-client'
|
||||||
|
|
||||||
|
const INFLUX_ORG = process.env.INFLUX_ORG
|
||||||
|
const INFLUX_BUCKET_AUTH = process.env.INFLUX_BUCKET_AUTH
|
||||||
|
const INFLUX_BUCKET = process.env.INFLUX_BUCKET
|
||||||
|
|
||||||
|
export default async function handler(req, res) {
|
||||||
|
try {
|
||||||
|
const deviceId = JSON.parse(req.body)?.deviceId
|
||||||
|
const devices = await createDevice(deviceId)
|
||||||
|
res.status(200).json(
|
||||||
|
Object.values(devices)
|
||||||
|
.filter((x) => x.deviceId && x.key) // ignore deleted or unknown devices
|
||||||
|
.sort((a, b) => a.deviceId.localeCompare(b.deviceId))
|
||||||
|
)
|
||||||
|
} catch(err) {
|
||||||
|
res.status(500).json({ error: `failed to load data: ${err}` })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates an authorization for a deviceId and writes it to a bucket */
|
||||||
|
async function createDevice(deviceId) {
|
||||||
|
let device = (await getDevices(deviceId)) || {}
|
||||||
|
let authorizationValid = !!Object.values(device)[0]?.key
|
||||||
|
if(authorizationValid) {
|
||||||
|
console.log(JSON.stringify(device))
|
||||||
|
return Promise.reject('This device ID is already registered and has an authorization.')
|
||||||
|
} else {
|
||||||
|
console.log(`createDeviceAuthorization: deviceId=${deviceId}`)
|
||||||
|
const authorization = await createAuthorization(deviceId)
|
||||||
|
const writeApi = influxdb.getWriteApi(INFLUX_ORG, INFLUX_BUCKET_AUTH, 'ms', {
|
||||||
|
batchSize: 2,
|
||||||
|
})
|
||||||
|
const point = new Point('deviceauth')
|
||||||
|
.tag('deviceId', deviceId)
|
||||||
|
.stringField('key', authorization.id)
|
||||||
|
.stringField('token', authorization.token)
|
||||||
|
writeApi.writePoint(point)
|
||||||
|
await writeApi.close()
|
||||||
|
return authorization
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an authorization for a supplied deviceId
|
||||||
|
* @param {string} deviceId client identifier
|
||||||
|
* @returns {import('@influxdata/influxdb-client-apis').Authorization} promise with authorization or an error
|
||||||
|
*/
|
||||||
|
async function createAuthorization(deviceId) {
|
||||||
|
const authorizationsAPI = new AuthorizationsAPI(influxdb)
|
||||||
|
const bucketsAPI = new BucketsAPI(influxdb)
|
||||||
|
const DESC_PREFIX = 'IoTCenterDevice: '
|
||||||
|
|
||||||
|
const buckets = await bucketsAPI.getBuckets({name: INFLUX_BUCKET, orgID: INFLUX_ORG})
|
||||||
|
const bucketId = buckets.buckets[0]?.id
|
||||||
|
|
||||||
|
return await authorizationsAPI.postAuthorizations({
|
||||||
|
body: {
|
||||||
|
orgID: INFLUX_ORG,
|
||||||
|
description: DESC_PREFIX + deviceId,
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
action: 'read',
|
||||||
|
resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'write',
|
||||||
|
resource: {type: 'buckets', id: bucketId, orgID: INFLUX_ORG},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue