Out-of-this-world monitoring with InfluxDB and React

Navigate to:

Reprinted with permission. © IDG Communications, Inc., 2021. https://www.infoworld.com/article/3609389/out-of-this-world-monitoring-with-influxdb-and-react.html

During an InfluxData internal hackathon, I was looking to work on a project that would help me strengthen my Telegraf and Flux skills. I also wanted to use InfluxData’s Giraffe to visualize my project in a React application. After reading Sean Brickley’s blog post on tracking the International Space Station with InfluxDB, I was inspired to build on this idea. So I landed on building a React application that could track the ISS’s position live and document its journey using InfluxDB, ExpressJS, Telegraf, and Giraffe.

There are three primary components for this project:

  1. The Telegraf config
  2. The ExpressJS API server
  3. The React application

Let’s start with the Telegraf config.

Like Sean, I used a public API to get the current position of the ISS. My plan was to use Telegraf to poll this API, parse the coordinate data, and send this location information to InfluxDB. I used Telegraf’s HTTP plug-in to achieve this. The next step was to parse the coordinate information from the JSON and convert the strings into floats. This can be accomplished with Telegraf’s Converter plug-in. And finally, I needed to send my location data to my InfluxDB cloud instance running in AWS. Naturally, this is easily done with Telegraf’s InfluxDB plug-in. Step one complete! Now we can run telegraf --config ./telegraf/iss.conf and start collecting the ISS’s location.

Now that we are beginning to collect some data, the next step is querying it. I decided to build an API using ExpressJS and to query my InfluxDB instance using the InfluxDB JS client. The goal here is to build an API that the React app can use to retrieve the location data that it will need to visualize the ISS’s flight path using Giraffe.

First we need to connect to InfluxDB, and we can do that by passing our URL and token to the InfluxDB object. Since we’re going to use the client to run queries, we need to get the Query API object. If you wanted to get bucket information, for example, you would want to get the Bucket API object instead.

const influxDB = new InfluxDB({ url: baseURL, token: influxToken })
const queryApi = influxDB.getQueryApi(orgID)

Next, we can use the InfluxDB JS client to query our InfluxDB instance like so:

app.get('/iss, (_, res) => {
 let csv = ''
 const issQuery = `todo`
 let clientQuery = flux``+issQuery
 queryApi.queryLines(clientQuery, {
   next(line) {
     csv = `${csv}${line}\n`;
   },
   error(error) {
     console.error(error)
     console.log('\nFinished /iss ERROR')
     res.end()
   },
   complete() {
     console.log('\nFinished /iss SUCCESS')
     res.end(JSON.stringify({ csv }))
   },
 })
})

This route will use the Query API object from the InfluxDB client to execute our query (which we haven’t defined yet). We’ll use the queryLines function to get our response back line by line. The resulting string will be a csv response that Giraffe can understand.

Great! Now we just need a Flux query. I experimented with several queries to try and see which one I thought highlighted the ISS’s movement the best. If I simply grabbed all the data over the past several hours, the Giraffe plot might be too busy. If I focused on trying to grab the data for one full orbit, there is a weird problem to solve with drawing a circular, continuous line across a flat map. So I ended up deciding to draw the ISS’s current orbit, from west to east, meaning I grabbed all the data points from 0 degrees longitude to its current position. The ISS orbits every 93 minutes, so I limited my query within that range. Here’s what I came up with:

import "experimental/geo"
 currentPos = from(bucket: "iss")
 |> range(start: -1m)
 |> filter(fn: (r) => r._field == "iss_position_longitude")
 |> tail(n: 1)
 |> findRecord(
   fn: (key) => true,
   idx: 0
 )
 
 from(bucket: "iss")
 |> range(start: -93m)
 |> aggregateWindow(every: 3m, fn: min, createEmpty: false)
 |> geo.shapeData(latField: "iss_position_latitude", lonField: "iss_position_longitude", level: 14)
 |> filter(fn: (r) => r.lon <= currentPos._value)
 |> geo.asTracks()

The query starts by finding the current longitude position of the ISS, which would be the most recent record. Then we query for all the positional data, aggregated into three-minute windows where the longitude is less than the ISS’s current position. We use Flux’s experimental Geo package to shape the data and to return the positional data as a track.

OK now on to the fun part — drawing the graph! I’m just going to cover the highlights, so feel free to check out the details of the implementation in the repo. Basically, we have a React application that is using InfluxData’s Giraffe visualization library. Giraffe recently added Geo plots with the ability to plot markers and tracks (check out the Storybook to play around with them). Our React application will query our API every 30 seconds or so to retrieve the latest data. We’ll use the fromFlux function to parse the response into a table that Giraffe can consume. As you can see from the Storybook, there are a lot of knobs you can tweak with the Geo plot. One important parameter is tileServerConfiguration, which tells Giraffe where to get the map images. I used OpenStreetMap and provided Giraffe the following object so it knows how to retrieve the correct map tiles:

const osmTileServerConfiguration = {
 tileServerUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
}

At this point, all the pieces are falling together! I added a checkbox into my UI to add the markers as an optional layer and also provided the ability to query for historical data of a custom time range.

Plotting the International Space Station's Orbit Live Using Telegraf, InfluxDB, and Giraffe

And there we have it — the ISS’s location updated live as it travels around the globe! Feel free to check out the source code and play with it yourself. Let me know if you find other Flux queries that produce interesting visualizations of this data.

As Sean mentioned in his post, the Geo features shown here are still experimental, but we’re working hard to get them ready for production. Stay tuned for more exciting updates in this space (pun intended)! If you’re working on a fun InfluxDB project like Sean and you need help please reach out on our community forum or Slack. We’d love to answer your questions and learn about what you’re doing with InfluxDB.