Grafana is a great piece of software for visualizing data and monitoring. It’s outstanding at what it does when paired with a time-series database like InfluxDB, except this time I’m trying to get it to work as a weather forecast dashboard, instead of any historical time-series data.

I choose CaiYun Weather (彩云天气) API for having previous experience with it, as well as its unlimited free tier. I must admit that I initially came up with this idea for having seen the presence of JSON API datasource plugin for Grafana, which reminds me of CaiYun’s JSON API being a perfect fit.

JSON API Datasource

Configuring the datasource seems easy at first, like just inserting the URL and configure HTTP headers as needed. Since CY’s API puts the API key in the URL path, there’s no headers to configure. So I can just put a single URL and save it.

https://api.caiyunapp.com/v2.5/TAkhjf8d1nlSlspN/121.6544,25.1552/hourly.json

I choose the hourly API so I can have forecast for the upcoming 48 hours.

So far this is a readily available datasource that I can query. But after reviewing the JSON query editor, I decided to chop off the last segments of the URL and leave just the part up to the API key:

https://api.caiyunapp.com/v2.5/TAkhjf8d1nlSlspN/

The point here is, the query editor allows specifying an extra Path, which appears to be concatenated with this URL in the datasource configuration. Notably, I can then put the coordinates in a variable, use it in the query, and build a single dashboard for many cities.

Dashboard variables

Now that I have the query format planned, I can add a dashboard variable for selecting cities.

First things first, since I’m going to use the same datasource for all panels, I first add a variable for the datasource and restrict it to “CaiYun Weather”:

Datasource variable

Then I add a variable $location for the city name, and provide it with a list of cities I want to show. The variable type would be “Custom” since this is just a human-maintained list. There certainly are better ways like using a relational database or an external API, making it easier to update, but for now I’d like to keep it simple.

Beijing : 116.4074\,39.9042,Shanghai : 121.4691\,31.2243,Guangzhou : 113.2644\,23.1291,Shenzhen : 114.0596\,22.5429

Panels

First and foremost, the most intuitive metric to show is temperature. I add a time series panel and configure it to graph the temperature. Start by building the query:

  • Datasource: Select ${datasource}
  • Query A:
    • Path: /${location}/hourly.json
    • Fields:
      • JSONPath: $.result.hourly.temperature[*].value, Type: Number, Alias: ${location:text}
      • JSONPath: $.result.hourly.temperature[*].datetime, Type: Time

I stumbled on getting the time series to display correctly. It wasn’t anywhere obvious in the documentation for the JSON API plugin, but a series with Type = Time is required. Fortunately, CY’s API returns the time in ISO 8601 format in the datetime field, so I can feed it directly to Grafana.

So far so good, except Grafana shows “No data”. I realized Grafana is trying to show past data, but apparently a weather forecast provides future data. I need to change the time range to “now” and “now + 48h”. Ideally, this time range is fixed and not affected by the time range selector, since after all it’s limited by the API.

This is another place where I spent half an hour on Google. The answer is “Relative time” in “Query options”. Its format, however, is again unintuitive. While community posts shows 1d for “last 1 day” and the official docs gives several examples on using now, none of them told me how to indicate “next 48 hours”. The answer is just +48h or +2d. Notably, entering now+48h would result in an error.

To make the graph look nicer, I set the unit to “°C”, limit decimals to 1, and set the Y-axis range to 0-40, and add a series of thresholds with colors to indicate the temperature range. Also worth mentioning is to make the graph change its color according to the temperature, so I set “Graph style → Gradient mode” to “Scheme” and “Standard options → Color scheme” to “From thresholds (by value)”.

Now this panel looks stunning.

Temperature panel

More panels

CY’s API offers a variety of weather data, so with little effort I can add more panels for humidity, precipitation and more, by duplicating the temperature panel and changing the query. I also need to change the unit and thresholds accordingly but that goes without saying.

There’s also a small piece worth displaying: A description text. It’s easy to put it in a “Stat” panel and display as “String” (instead of “Number”). And better yet, CY provides two descriptions: One for the next two hours, and one for the next two days. Two panels for two pieces of text, yeah.

One last thing I decided to leave out for now: The skycon field that describes the weather condition, like “CLEAR_DAY” or “RAIN”. It’d be comparably easy to add a panel for it, using “Value mapping” to change the text to something more human-readable, but I’m not at the high mood for it right now, so maybe I’ll pick it up later.

Results

Now I have a nice dashboard for viewing weather forecast for multiple cities:

Dashboard

If you’d like to try it yourself, I’ve published the dashboard on Grafana.com: Weather Forecast. Just add the same datasource with your API key, and you can import my dashboard and start getting weather forecast for yourself.

Leave a comment