# Dashboard your TimescaleDB data with Grafana

- URL: https://baeke.info/2019/04/18/dashboard-your-timescaledb-data-with-grafana/
- Author: Geert Baeke
- Published: April 18, 2019 (updated March 12, 2025)
- Topics: analytics, iot, dashboards, grafana, iot, timescale

In an [earlier post](https://baeke.info/2019/04/15/iot-with-azure-database-for-postgresql-and-timescaledb/), I looked at storing time-series data with [TimescaleDB](https://www.timescale.com/) on [Azure Database for PostgreSQL](https://docs.microsoft.com/en-us/azure/postgresql/). To visualize your data, there are many options as listed [here](https://docs.timescale.com/v1.2/using-timescaledb/visualizing-data). Because TimescaleDB is built on PostgreSQL, you can use any tool that supports PostgreSQL such as Power BI or Tableau.

Grafana is a bit of a special case because TimescaleDB engineers actually built the data source, which is designed to take advantage of the time-series capabilities. For a detailed overview of the capabilities of the data source, see the [Grafana documentation](https://grafana.com/docs/features/datasources/postgres/).

Let’s take a look at a simple example to get started. I have a [hypertable](https://docs.timescale.com/v1.2/using-timescaledb/hypertables) called conditions with four columns: time, device, temperature, humidity. An [IoT Simulator](https://github.com/gbaeke/iot-simulator) is constantly writing data for five devices: pg-1 to pg-5.

On a [multi-tier deployment](https://baeke.info/?p=1249) of Grafana, I added the PostgreSQL data source:

![](https://baeke.info/_astro/2019-04-image-34.7UPJhMl__ZxeTCm.webp)

*PostgreSQL data source in Grafana*

One setting in the data source is particularly noteworthy:

![](https://baeke.info/_astro/2019-04-image-35.Ctvw3b_6_Z1qAW55.webp)

*TimescaleDB support in the PostgreSQL datasource*

Grafana has the concept of macro’s such as $\_timeGroup or $\_interval, as noted in the preceding image. The macro is translated to what the underlying data source supports. In this case, with TimescaleDB enabled, the macro results in the use of [time\_bucket](https://docs.timescale.com/v1.2/api#time_bucket), which is specific for TimescaleDB.

## Creating a dashboard

Create a dashboard from the main page:

![](https://baeke.info/_astro/2019-04-image-36.DSeoO4r3_Z2biOVn.webp)

*Creating a new dashboard*

You will get a new dashboard with an empty panel:

![](https://baeke.info/_astro/2019-04-image-37.CC93f1RP_ZY2KOo.webp)

Click **Add Query**. You will notice Grafana proposes a query. In this case it is very close because we only have one data source and table:

![](https://baeke.info/_astro/2019-04-image-38.Zz9uSi4f_23MdY8.webp)

*Grafana proposes the following query*

Let’s modify this a bit. In the top right corner, I switched the time interval to last 30 minutes. Because the default query uses **WHERE Macro: $\_timeFilter**, only the last 30 minutes will be shown. That’s another example of a macro. I would like to show the average temperature over 10 second intervals. That is easy to do with a GROUP BY and $\_interval. In GROUP BY, click the + and type or select time to use the time field. You will notice the following:

![](https://baeke.info/_astro/2019-04-image-39.DnH4_VkG_Z1UvKlz.webp)

*GROUP BY with $\_interval*

Just click $\_interval and select 10s. Now add the humidity column to the SELECT statement:

![](https://baeke.info/_astro/2019-04-image-40.S1zyVUcK_Z1xRK9B.webp)

*Adding humidity*

When you click the **Generated SQL** link, you will see the query built by the query builder:

![](https://baeke.info/_astro/2019-04-image-41.CIdn-nyV_4dfJP.webp)

*Generated SQL*

Notice that the query uses time\_bucket. The GROUP BY 1 and ORDER BY 1 just means group and order on the first field which is the time\_bucket. If the query builder is not sufficient, you can click **Edit SQL** and specify your query directly. When you switch back to query builder, your custom SQL statement might be overwritten if the builder does not support it.

When you save your dashboard, you should see something like:

![](https://baeke.info/_astro/2019-04-image-42.zFKIBXsR_Z2bMkHG.webp)

*Pretty boring temperature and humidity graphWi*

Now, let’s add a few gauges. In the top right row of icons, the first one should be Add panel. Choose the Gauge visualization and set your query:

![](https://baeke.info/_astro/2019-04-image-43.BWv_8RFj_K1U6d.webp)

*Temperature Gauge*

In Visualization, set **Stat** to **Current**:

![](https://baeke.info/_astro/2019-04-image-44.C-nUjIJk_LAvGU.webp)

*Stat field on current*

When the panel is finished, navigate back to the dashboard and duplicate the gauge. Modify the duplicated gauge to show humidity. Also change the titles. The dashboard now looks like:

![](https://baeke.info/_astro/2019-04-image-45.DFVxthpz_Z1Jm47r.webp)

*Conditions dashboard*

Grafana can be configured to auto refresh the dashboard. In the image below, refresh was set to every 5 seconds:

![](https://baeke.info/_astro/2019-04-image-46.DlaqL8oW_1kHsEd.webp)

*Setting auto refresh*

Your dashboard will now update every 5 seconds for a more dynamic experience.

## Joins

You can join hypertables with regular tables quite easily. This is one of the advantages of using a relational database such as PostgreSQL for your time-series data. The screenshot below shows a graph of the temperature per device location. The device location is stored in a regular table.

![](https://baeke.info/_astro/2019-04-image-49.CTM71Z6d_Z1nqsOM.webp)

*Join between hypertable and regular table: they are all just tables in the end*

Here is the full dashboard:

![](https://baeke.info/_astro/2019-04-image-48.BOLmpntF_U5hqh.webp)

## Conclusion

Grafana, in combination with PostgreSQL and TimescaleDB, is a flexible solution for dashboarding your IoT time-series data. We have only scratched the surface here but it’s clear you can be up and running fast! Give it a go and tell me what you think in the comments or via [@geertbaeke](https://twitter.com/GeertBaeke)!
