Hoppa till huvudinnehåll

Grafana

The IoT platform supports two Grafana data sources:

  1. JSON data source (simpod-json-datasource) - host your own Grafana and view time-series data from the platform.
  2. Infinity data source - use any of the IoT platform's REST API endpoints to build tables, charts and maps, and drive Grafana's alert manager.

This guide shows how to build panels. To install and connect Grafana first, see Grafana Setup. If you don't have access to Grafana from your platform account, ask an admin to grant it or contact your technical support.

Which data source should I use?

Use the…when you want to…
JSON data sourcequickly graph a device's values or plot devices on a map (device selected as a "metric")
Infinity data sourcepull any REST API response into a table, build charts/maps from arbitrary endpoints, or set up alerting

Field names are the IoT platform's canonical fields (temperature, rssi, lnglat, …), so a panel built for one device works for others of the same kind.


Build panels with the JSON data source

Time-series graph

  1. Choose Time series as the visualization (top-right).
  2. Choose the metric (the IoT node / device) you want to graph.
  3. Choosing the wildcard metric (*) graphs values from all your active devices.

Hide lat / lng from a graph

If a device has an lnglat field, its lat and lng show up on the time-series graph. To hide them:

A Grafana time-series graph from the JSON data source, with lat and lng hidden

  1. Make sure a metric (device) is selected.
  2. Click Transform.
  3. Choose Filter by name.
  4. Uncheck lat and lng.

Map (Geomap)

  1. Choose Geomap as the visualization (top-right).
  2. Choose the metric (device) to plot.
  3. Make sure lat and lng are checked (opposite of the previous step).
  4. Choosing the wildcard metric (*) plots all your active devices' GPS positions - after selecting the Merge option under Transform.

Tracker location history

  1. Choose Geomap as the visualization (top-right).
  2. Choose the metric Your Tracker.lnglat - this draws the track on the map automatically.
  3. Optionally add a second query, Your Tracker.speed, to colour-code the track.
  4. In the Marker side panel, select the value to colour-code by and set the thresholds.

A Grafana Geomap panel plotting a tracker's location history, colour-coded by thresholds tracker map coloured by value


Build panels with the Infinity data source

The Infinity data source calls the IoT platform's REST API directly. The easiest way to learn it: copy a complete request URL from Swagger (https://staging.yggio.net/swagger), paste it into the panel, then add columns using the field names from the JSON response (visible in Swagger) and set each column's data type. Click refresh to try it.

Table

  1. Choose Table as the visualization (top-right).
  2. Enter the GET URL https://staging.yggio.net/api/iotnodes. To filter, add a q query - e.g. https://staging.yggio.net/api/iotnodes?q=temperature returns only devices that have a temperature field.
  3. Under Parsing options & Result fields, enter the columns you want, e.g.:
    • name as Name, type String
    • reportedAt as Reported, type Time
    • rssi as RSSI, type Number
    • snr as SNR, type Number

A Grafana table panel built on the Infinity data source, with the parsed device columns The same Infinity table panel with more rows and columns filled in

To include contextual parameters, add selector columns like contextMap.yourFieldName:

An Infinity table panel with a contextMap field added as a column

To show the same data as a bar chart, just change the panel type to Bar chart:

The same Infinity data shown as a bar chart panel

Time series

  1. Choose Time series as the visualization (top-right).
  2. Enter the GET URL https://staging.yggio.net/api/iotnodes/<device _id>/stats?measurement=temperature&start=<start time in unix ms>&distance=3600 to get the temperature time series (distance is the bucket size in seconds).
  3. Under Parsing options & Result fields, map the columns:
    • value as value, type Number
    • time as time, type Time

A Grafana time series panel on the Infinity data source, with time parsed as the Time field The same Infinity time series panel over a longer period

Map (Geomap)

  1. Choose Geomap as the visualization (top-right).
  2. Enter the GET URL https://staging.yggio.net/api/iotnodes?q=lnglat to get devices that have a valid location.
  3. Under Parsing options & Result fields, map the location and the values to plot - e.g. for a signal-strength map:
    • lnglat.coordinates.0 as Longitude, type Number
    • lnglat.coordinates.1 as Latitude, type Number
    • rssi as RSSI, type Number
    • snr as SNR, type Number
  4. Add thresholds to colour-code the map.

A Grafana Geomap panel on the Infinity data source, with devices colour-coded by threshold The same Infinity Geomap panel zoomed in on a single site


Choosing a panel type

Grafana has many visualizations. For the IoT platform's data, these are the common choices:

To show…UseNotes
A value trending over time (temperature, energy, humidity)Time seriesthe default for metrics
The latest single value, big and bold (current temp, battery %)Statadd thresholds to colour it; shows a sparkline
A value within a known range (battery %, tank fill, humidity)Gaugeset min/max and thresholds
The same value across many devices (battery of every sensor)Bar gaugeone bar per device - wildcard metric * + a Reduce transform
A list of devices and their fieldsTableInfinity → /api/iotnodes
Device locations, tracker paths, heatmapsGeomapneeds lnglat (lat/lng)
A boolean / on-off state over time (occupancy, door, alarm)State timelineideal for presence, contact, *Alarm fields
Counts or categories side by side (people per zone)Bar chart
The distribution/spread of a measurementHistogram
Current alertsAlert listpairs with Infinity alert rules

Tips & techniques

  • Set the unit (Panel → Standard options → Unit, e.g. Celsius (°C), Percent (0-100), Volts) so axes, tooltips and Stat/Gauge render correctly.
  • Thresholds (Panel → Thresholds) colour Stat / Gauge / Time series by value - e.g. temperature turns red above 30 °C, battery amber below 20 %.
  • Value mappings (Panel → Value mappings) turn numbers into words - map 0 → Closed / 1 → Open, or false → Vacant / true → Occupied for boolean fields like contact or presence.
  • Transformations do most of the shaping without changing the query:
    • Filter by name - hide fields such as lat / lng.
    • Merge - combine wildcard (*) results into one series or table.
    • Organize fields - rename, reorder and hide columns.
    • Reduce - collapse a time series to its last / max / mean (feeds a Stat or Bar gauge).
    • Add field from calculation - derived columns (difference, ratio, etc.).
  • Device dropdown (dashboard variables): in Dashboard settings → Variables create a variable of device names, then reference it in your queries so one dashboard serves any device. Combine with Repeat (Panel → Repeat options) to auto-generate one panel per selected device.
  • Navigation between dashboards: link dashboards together to build a landing-page → drill-down experience. Options, simplest first:
    • Text panel - plain Markdown links to other dashboards.
    • Dashboard list panel - auto-lists dashboards by tag or folder, no config.
    • Data links / panel links - click a series or panel to jump to another dashboard, carrying the current variables (e.g. the selected device).
    • Business Text panel (Volkov Labs, community plugin marcusolsson-dynamictext-panel) - the powerful option: render custom Markdown/HTML from your query data, so you can build a data-driven navigation menu (e.g. one link per device, generated from a device list, each passing that device into the target dashboard's variables). Install it first: grafana-cli plugins install marcusolsson-dynamictext-panel, then restart.
  • Auto-refresh & time range: set the dashboard refresh (e.g. every 1 m) and a sensible default range (top-right) - Last 24 hours is a good start.
  • Legend values: show last / mean / max in the legend (Panel → Legend) for quick at-a-glance numbers.
  • Alerting (Infinity only): you can alert on any REST value - thresholds, or offline devices via No data - see Set up a simple alert.
  • Public dashboards (embed in a website, no login): a public dashboard runs queries with no logged-in user, so it can't query the IoT platform directly - the data must first be copied into your own store. See Publish on a public dashboard.

Common recipes

End-to-end examples that combine the steps above - copy the settings.

Current temperature, colour-coded (Stat)

  1. New panel → Stat. JSON data source → pick the device → field temperature.
  2. Standard options → Unit = Celsius (°C).
  3. Thresholds: base green, add red at 30, blue at 0. → A big current-temperature number that turns red when it's hot.

Battery level of every sensor (Bar gauge)

  1. New panel → Bar gauge. JSON data source → metric * → field batteryLevel.
  2. Transform → Reduce = Last (one value per device).
  3. Unit = Percent (0-100); Thresholds: red <20, amber <50, else green. → One bar per sensor - instantly shows which batteries are low.

Occupancy over time (State timeline)

  1. New panel → State timeline. Pick the device → field presence (or occupied).
  2. Value mappings: true → Occupied, false → Vacant (give each a colour). → A coloured ribbon showing when the space was occupied.

Alert when a device goes offline - set up an Infinity alert rule (see Set up a simple alert) and use its No data → Alerting option, so you're notified when a sensor stops reporting.

Fleet overview table (Table via Infinity)

  1. New panel → Table. Infinity data source → GET https://staging.yggio.net/api/iotnodes (add ?q=batteryLevel to limit it to your sensors).
  2. Parsing options & Result fields - add the columns:
    • name as Device, type String
    • batteryLevel as Battery %, type Number
    • rssi as RSSI, type Number
    • snr as SNR, type Number
    • reportedAt as Last reported, type Time
  3. Colour the battery column: add a field override on Battery % → Cell display mode = Colored background, with Thresholds red <20, amber <50, else green.
  4. Surface silent devices: sort the table by Last reported (click the column header, or set it as the default sort) so the least-recently-seen devices rise to the top. → One row per device showing battery, signal and last-seen - an at-a-glance fleet-health view.

Energy consumption per day (Bar chart)

  1. Run the calculate-energy-consumption-per-time-period translator on the meter
    • it turns the cumulative activeEnergyImport reading into energyConsumptionDay / Week / Month (each resets at local midnight). See Translator Development.
  2. New panel → Bar chart (or Time series). JSON data source → pick the meter → field energyConsumptionDay.
  3. Unit = kWh (kilowatt-hour); optionally add thresholds to flag high-usage days. → Each day's consumption; the value just before midnight is that day's total.

No translator on the meter? Query the raw cumulative reading per day via Infinity - /stats?measurement=activeEnergyImport&distance=86400 - then take the day-over-day difference in Grafana. The IoT platform's /stats buckets by distance but doesn't difference server-side, so the translator route above is simpler.


Set up a simple alert (Infinity)

Grafana can alert on any of the IoT platform's REST data through the Infinity data source. Here is a minimal threshold alert - "notify me when a temperature goes above 30 °C" - using Grafana's unified alerting (Grafana 9+).

  1. Create a contact point (once): Alerting → Contact points → Add contact point. Choose a type (email, Slack, webhook, …), fill in the details, and test it.
  2. New alert rule: Alerting → Alert rules → New alert rule, and name it.
  3. Query the value (query A): choose the Infinity data source and enter a GET URL that returns the number to watch, e.g. https://staging.yggio.net/api/iotnodes/<device _id>/stats?measurement=temperature&start=<ms>&distance=3600 (parse value as a Number). Run it to confirm it returns data.
  4. Reduce to one value (expression B): add a Reduce expression, function Last, input A. Alert rules evaluate a single number, not a whole series.
  5. Set the threshold (expression C): add a Threshold expression on B, e.g. IS ABOVE 30, and set C as the alert condition.
  6. Evaluation: put the rule in an evaluation group with an interval (e.g. every 1 m) and a pending period (e.g. 5 m) so a brief spike doesn't fire immediately.
  7. Notifications: add a summary annotation (the message you'll receive), then make sure the rule's labels match a notification policy that routes to your contact point (the default policy routes everything to the default contact point, which is the simplest start).
  8. Save. When the temperature stays above 30 °C for the pending period you get a notification; it resolves automatically when the value drops back.

Offline-device alerts: in the rule's Configure no data and error handling, set the state to Alerting when the query returns No data. Paired with a query that only returns recent data, this notifies you when a device stops reporting.


Publish on a public dashboard

You can put a dashboard on a public URL and embed it in a website so anyone can see it without logging in - for live air quality, water levels, parking occupancy, and the like.

The one thing to understand first

A public dashboard runs its queries server-side, with no logged-in user. The IoT platform, by design, never returns data without authorization, so a public (userless) dashboard cannot query the IoT platform directly - the JSON and Infinity data sources above rely on your being logged in, which a public viewer is not.

So the data has to already be sitting in a store Grafana can read without a login to the IoT platform. The pattern: copy the live data out of the IoT platform into your own InfluxDB, and point the public dashboard at InfluxDB. A small Node-RED flow does the copying - and because it authenticates to the IoT platform's MQTT broker with a Basic Credential Set (a durable username/password, not a user session), it runs unattended. The public viewer never touches the platform.

Yggio MQTT output ──(Basic Credential Set)──▶ Node-RED ──▶ InfluxDB ──▶ public dashboard ──▶ iframe
durable auth bridge flow no Yggio auth in the public path

Many teams already run Node-RED, so this usually reuses infrastructure you have.

Prerequisites

  • A Node-RED install that can reach the IoT platform's MQTT broker (Node-RED guide).
  • An InfluxDB instance (a single Docker container is fine - Step 1).
  • A self-hosted Grafana reachable from the internet (reverse proxy + HTTPS).
  • In the IoT platform: a Basic Credential Set and an MQTT channel on each device you want to publish (MQTT reference).

Step 1 - Stand up InfluxDB

If you don't already have one:

docker run -d --name influxdb -p 8086:8086 \
-v influxdb-data:/var/lib/influxdb2 \
influxdb:2

Open http://<host>:8086, run the setup wizard, and note four things you'll reuse: the URL, the organization, an API token, and a bucket name (e.g. yggio-public). Use a separate bucket per customer so each public dashboard only ever exposes its own devices.

Step 2 - Build the Node-RED bridge

  1. Install the InfluxDB nodes: Manage palette → Install → node-red-contrib-influxdb.

  2. MQTT in node - add an MQTT server for the IoT platform's broker:

    • Server mqtt.staging.yggio.net, Port 8883, TLS enabled.
    • Security: the Basic Credential Set username/password.
    • Topic: the topic from the device's MQTT channel in the IoT platform (device → Channels tab → basicCredentialSet channel → copy the topic). See the MQTT reference.
    • Set Output to "a parsed JSON object" so msg.payload is an object.
  3. Function node - turn the reading into an InfluxDB point, keeping only the devices you intend to publish:

    // Only these devices are allowed onto the public dashboard.
    const PUBLIC = ['device-id-1', 'device-id-2'];

    const deviceId = msg.topic.split('/').pop(); // or read from msg.payload
    if (!PUBLIC.includes(deviceId)) { return null; } // drop everything else

    // Keep numeric canonical fields only (temperature, batteryLevel, ...).
    const fields = {};
    for (const [k, v] of Object.entries(msg.payload)) {
    if (typeof v === 'number') { fields[k] = v; }
    }
    if (Object.keys(fields).length === 0) { return null; }

    msg.payload = [fields, {deviceId}]; // node-red-contrib-influxdb: [fields, tags]
    return msg;
  4. InfluxDB out node - select your InfluxDB server (URL, token, org), set the bucket and a measurement name (e.g. reading).

  5. Deploy. Readings now flow into InfluxDB.

Don't lose data if InfluxDB blips. The bridge is the one spot Node-RED doesn't buffer for you. For resilience, batch writes and add a small retry (a catch node feeding a retry path). For a few devices at a slow report rate this rarely matters - size it to your fleet.

Step 3 - Add InfluxDB as a Grafana data source

Pure UI, no plugin to install (InfluxDB is built into Grafana): go to Connections → Data sources → Add data source → InfluxDB, then set the query language (Flux for InfluxDB 2), the URL http://<influx-host>:8086, and the auth (token, organization, default bucket). Click Save & test.

Step 4 - Build the dashboard

Add panels querying InfluxDB. A minimal Flux query for one field:

from(bucket: "yggio-public")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "reading" and r._field == "temperature")

Set the dashboard auto-refresh (e.g. 10 s) for a live feel.

Step 5 - Make the dashboard public

On self-hosted (community) Grafana, add to grafana.ini:

[security]
allow_embedding = true

# Only on older Grafana (9.x / 10.0–10.1); ~10.2+ has it on by default.
[feature_toggles]
publicDashboards = true

Restart Grafana, then on the dashboard choose Share → Public dashboard → enable and copy the public URL. (In Grafana 11/12 this is under Share → External / Shared dashboard - same feature, renamed.)

Step 6 - Embed it in the website

Drop the public URL into an <iframe> in the site's CMS:

<iframe src="https://GRAFANA_HOST/public-dashboards/<token>"
width="100%" height="600" frameborder="0"></iframe>

Security, isolation and limits

  • Exposure: a public dashboard shows everything in its bucket to anyone with the link - there is no per-viewer filtering. Keep each customer's data in its own bucket, and only let the bridge write the devices in the PUBLIC allow-list.
  • Credentials: the bridge's Basic Credential Set is a real credential for the IoT platform - protect the Node-RED instance (keep it behind a firewall; it has only a simple login).
  • Feature limits: public dashboards don't support template variables, some panel types are unavailable, and results are cached - fine for fixed "current readings + recent trend" displays, less so for interactive exploration.
  • Latency: "real-time" is driven by the refresh interval plus that cache, not sub-second streaming; InfluxDB ingest itself is fast.
  • History: InfluxDB only holds data from when the bridge starts. To backfill, do a one-time load from the IoT platform's /stats endpoint (see Accessing the IoT platform's API).