{endpoint}/api/v0/exec. Your READ token is stored encrypted by Grafana and never reaches the browser.

- The y-axis reads kW. The unit comes from the
engUnitsattribute in the Nexalis data model, applied to the field automatically. - The legend names itself from the series-name template — site, asset type, measurement, device and sub-device, with any part a series does not have dropped.
- Auto bucket resolved to the 1-minute step Grafana asked for, shown as
Interval = 1munder Query options. Widen the time range and the bucket widens with it, so the amount of data crossing the wire stays roughly constant.
The Grafana plugin is currently a preview (beta) release. Query options and the saved query format may still change between builds, so a dashboard built now may need small adjustments after an upgrade. Please send feedback and issues to contact@nexalis.io.
- A point-and-click query editor — no WarpScript knowledge required
- Filter dropdowns populated from your own tenant, each one narrowed by the filters you already picked
- The Nexalis macros (
@nexalis/fetch_bucketized,@nexalis/fetch_trapezoidal_averages,@nexalis/scale) exposed as query types - Dashboard variables driven by your real site and device lists
- A raw WarpScript editor for anything the query builder does not cover
Requirements
- Grafana 12.3 or newer, self-hosted (OSS or Enterprise)
- Access to the Grafana server’s filesystem, and the ability to restart it
- A Nexalis Cloud endpoint URL and a READ token
- Outbound HTTPS from the Grafana server to your endpoint
Grafana Cloud is not supported yet. Grafana Cloud only runs plugins signed and published in the Grafana catalog, and this plugin is not yet signed. Use a self-hosted Grafana for now.
Installation
Whichever way you run Grafana, the shape is the same: put the plugin folder where Grafana looks for plugins, tell Grafana to trust it because it is not signed yet, and restart. Only the mechanics differ, so pick the track that matches your setup:- Grafana as a system package — installed with
aptoryum, managed bysystemd - Grafana in Docker —
docker runor Docker Compose
Step 1: Find the latest version (both tracks)
Open the releases repository and note the version number of the newest release — the tag looks likev1.1.0, and the download is nexalis-nexalis-datasource-1.1.0.zip.
Each release also publishes a .zip.sha1 file if you want to verify the download:
Whatever you do, keep the
nexalis-nexalis-datasource/ folder name from the zip. Grafana identifies a plugin by the plugin.json inside its own folder — renaming or flattening the folder stops it loading.Track A: Grafana installed as a package
A1. Unzip into the plugins directory
The default is/var/lib/grafana/plugins. To confirm the path your server actually uses, ask Grafana — it logs every path at startup:
On a fresh Grafana this directory does not exist yet. Grafana creates
/var/lib/grafana for its database, but plugins/ only appears once a plugin has been installed, so cd /var/lib/grafana/plugins fails with “No such file or directory”. The mkdir -p below handles that./tmp as your own user, and only the unzip needs sudo — the plugins directory is owned by root. The final chown matters: Grafana runs as the grafana user and silently skips a plugin directory it cannot read.
You should end up with a nexalis-nexalis-datasource/ folder containing plugin.json, module.js and several gpx_nexalis_datasource_* backend binaries.
A2. Allow the plugin to load
The plugin is not signed yet, so add its ID tografana.ini:
A3. Restart Grafana
plugin.json only at startup, so a restart is required — after this install and after every upgrade. Now jump to Confirm Grafana found it.
Updating (package)
Replace the folder with the newer release and restart:grafana.ini does not need changing again.
Removing (package)
allow_loading_unsigned_plugins.
Track B: Grafana in Docker
Nothing is installed inside the container. You unpack the plugin on the host and mount that one folder in, which means an upgrade is a host-side file swap plus a container restart.B1. Unpack the plugin on the host
Pick a directory you control — this example uses./grafana-plugins next to your docker-compose.yml:
B2. Mount it and allow it
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS is the environment-variable form of the grafana.ini setting — in Docker you never edit the file.
Two details worth getting right:
- Mount the plugin’s own folder, not the whole
pluginsdirectory. Mounting the parent would hide any other plugin the image ships with. - Give
/var/lib/grafanaa named volume. Without it, your data sources and dashboards are inside the container’s writable layer and disappear the moment you recreate it — which is exactly what an upgrade does.
docker run, useful for a quick trial:
B3. Start it
Updating (Docker)
Replace the folder on the host, then restart the container. Grafana readsplugin.json only at startup, so the restart is what actually applies the new version:
/var/lib/grafana is on a named volume.
Removing (Docker)
Delete thevolumes: line for the plugin from your compose file, then:
Confirm Grafana found it
In Grafana, go to Connections → Data sources → Add new data source and search forNexalis. If it appears, the plugin is loaded — continue to Connecting to Nexalis Cloud.
To check the version that is actually running, open Administration → Plugins and search for Nexalis.
If it does not appear at all, see The Nexalis data source does not appear.
Connecting to Nexalis Cloud
Go to Connections → Data sources → Add new data source and choose Nexalis. There are only two fields to fill in:
Then click Save & test.
A working configuration reports how many time series the token can see:
Use a READ token. The plugin only ever queries data and never writes to your Nexalis instance.The token is stored in Grafana’s encrypted secrets store. Once saved it is write-only: the field shows
configured and you can replace it, but neither the browser nor a dashboard viewer can read it back.https://yourcompany.app.nexalis.io) or the full exec URL (https://yourcompany.app.nexalis.io/api/v0/exec) — the plugin normalises it either way.
Provisioning instead of clicking
To create the data source from configuration, drop a file in Grafana’sprovisioning/datasources/ directory:
NEXALIS_READ_TOKEN in the Grafana server’s environment so the token is not committed to your configuration repository.
Your first panel
This builds a chart of inverter AC power for one site, from an empty dashboard.- Go to Dashboards → New → New dashboard, then click + Add visualization
-
Choose your Nexalis data source
The query editor opens with Query type set to Bucketized values and one empty filter row keyed on
siteName. - Click the value box on that first filter row The dropdown lists the real site names in your tenant. Pick one.
-
Click the + button at the end of the row to add a second filter. Set the key to
assetTypeand the value toINV -
Add a third filter: key
dataObject, valueTotW - Set the dashboard time range in the top right to Last 6 hours
- Click the refresh button
engUnits from the Nexalis data model and applies it to the panel. The screenshot at the top of this page shows the same thing, narrowed further with logicalNode and deviceID filters as well.
Click Save to keep the dashboard.
A filter with an empty value matches nothing, which is why a brand-new panel shows no data until you fill in that first value. If a panel goes empty after an edit, check that every filter row you have added has a value.
The query editor
Query types
Bucketized and trapezoidal are the two you will use most. Both aggregate server-side, so the amount of data crossing the wire stays roughly constant however long a time range you pick.
Filters
Filters are the heart of a query. Each row is one key and one value, and all rows are combined — a query matches series that satisfy every row. Nexalis stores two kinds of metadata on a time series, labels and attributes, and both are filterable here in exactly the same way:
See Data Structure for what each one means.
Both the key and the value dropdowns are populated from your tenant, and the value list is narrowed by the filters you have already set — pick
siteName first and the assetType dropdown then offers only the asset types that exist at that site. Building a query top to bottom keeps every choice valid.
You can also type instead of picking:
- A Warp10 regular expression, prefixed with
~—~INV-(1|2),~^TX_,~.*_001$. See Filtering Data. - A dashboard variable —
$site. See Dashboard variables below.
Bucket size
Auto bucket is on for new queries. The bucket width then follows the panel’s time range and width the way Grafana’s$__interval does, snapping to a fixed ladder — 1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720 or 1440 minutes — so buckets do not shift around as you resize a panel.
Turn Auto bucket off to pin a width in minutes, which is what you want when a number has to mean something specific: 15-minute averages for a settlement report, say, regardless of how the panel is displayed.
Bucketizer
For Bucketized values, the Bucketizer field decides how the points inside each bucket are reduced to one value:
If what you actually need is a time-weighted average — the true average of the signal over the bucket, rather than of the samples — use the Trapezoidal averages query type instead. On irregularly-sampled tags the two give different answers, and the trapezoidal one is the correct one.
Scaling
Scaling is on by default and applies@nexalis/scale, which converts each raw SCADA value into the engineering units of the Nexalis data model using the multiplier and adder attributes — watts to kilowatts, for instance. Leave it on unless you specifically want the raw stored values.
Series name
Series name controls the legend. It is a template with${...} placeholders, and any label or attribute can be used:
${subDeviceID} alone is usually the readable choice.
Dashboard variables
A variable turns a hard-coded filter into a dropdown at the top of the dashboard.- Open Dashboard settings → Variables → Add variable
- Set Select variable type to Query and give it a name, for example
site - Choose your Nexalis data source
- Set Query type to Discover (FIND)
- Set Return values of to
siteName - Check the preview at the bottom of the page — it lists your actual site names
- Apply, then use it in any panel by typing
$siteas a filter value
assetType, deviceID or dataObject to build those dropdowns. Add filters to the variable query to make one variable depend on another — give the deviceID variable a filter of siteName = $site, and it will only ever list devices at the selected site.
Multi-value and “All” work. The plugin translates a multiple selection into a Warp10 regular expression (
~^(TX_001|TX_002)$), because Warp10 has no list syntax of its own. You do not have to do anything — write $site as the filter value and select as many as you like.Raw WarpScript
Choose Raw WarpScript as the query type to write the script yourself. The filter builder is hidden — your script defines its own selectors. The plugin injects your saved token and the panel’s time range, so a script can be moved between dashboards and time ranges unchanged:Query performance
Nexalis is a time-series database: it is fast at reading one tag over a long period, and slow at reading many tags at once. The best practices apply directly to how you build panels.- Filter as narrowly as you can. Every filter you add cuts the number of series the API has to scan. Always set
siteName; adddeviceIDordataPointwhen you know them. - One chart, one question. A panel filtered only by
siteNameandassetTypecan match thousands of series. When a query returns more than 500, the panel shows a warning explaining that this is why it is slow — treat it as a prompt to add a filter, not as an error. - Prefer the aggregating query types. Bucketized and trapezoidal aggregate server-side. Raw values (scaled) returns every recorded point, which on a high-frequency tag over a week is an enormous amount of data.
- Mind the dashboard refresh rate. Every panel is a separate API call. A dashboard of twenty panels refreshing every ten seconds is 120 calls a minute, which can hit your rate limit.
Troubleshooting
The Nexalis data source does not appear
Grafana logs a reason at startup. Check it first — it usually names the problem outright:- Was Grafana restarted after the plugin was unzipped?
plugin.jsonis read only at startup. - Is the folder in the right place, and still named
nexalis-nexalis-datasource? Theplugin.jsonmust be at<plugins-dir>/nexalis-nexalis-datasource/plugin.json, not one level deeper. Unzipping a second time can produce a nested duplicate folder. - Is the plugin allowed? A signature error in the log means
allow_loading_unsigned_pluginsis missing the ID, or — in Docker — thatGF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINSis missing or misspelled. - Are the backend binaries executable? A “failed to start plugin” error usually means the
gpx_*files lost their executable bit. Runchmod +x <plugins-dir>/nexalis-nexalis-datasource/gpx_*. - Can Grafana read the folder? On a package install it must be readable by the
grafanauser. In Docker it must be readable by UID 472, which host ownership does not translate to —chmod -R a+rXon the host folder is the quick fix. - In Docker, is the mount actually there? Confirm what the container sees:
An empty or missing directory means the
volumes:path is wrong — it is resolved relative to the compose file, not to your shell.
”Save & test” fails
A panel shows no data
Work from the widest query inwards:- Check the time range. A device that stopped reporting has no data in the last hour, however correct the filters are.
- Remove filters one at a time. The one whose removal brings data back is the one that does not match. Values are case-sensitive and exact unless prefixed with
~. - Make sure no filter row has an empty value — an empty value matches nothing.
- Switch Query type to Discover (FIND) with the same filters and set Return values of to
dataPoint. If that returns nothing, no series matches your filters at all; if it returns series, the filters are fine and the issue is the time range or the query type. - If a variable is involved, confirm it has a selected value — an unset variable interpolates to nothing.
Other errors
too much data returned / response exceeded 50 MB. The query matched too many series or too long a range. Narrow the filters or shorten the time range. Switching from Raw values (scaled) to Bucketized values usually fixes it on its own.
rate limited by Nexalis (HTTP 429). Too many calls in too short a window. Lower the dashboard refresh rate, or reduce the number of panels querying at once.
query failed on Nexalis (HTTP 500). The catch-all for a WarpScript error. The rest of the message is Warp10’s own, naming the function that failed — most often a Raw WarpScript query with a typo, or a macro called with the wrong parameters. Common Errors lists the API-level causes.
A boolean or text tag shows as a flat line at 0 and 1. That is expected: Discrete measurements such as alarm states and nexalisConnectionStatus are plotted as 1 for true and 0 for false. The State timeline visualisation reads better than a time series for these. Text-valued tags come through as text, best viewed in a Table.
Gaps in a trapezoidal-average line. The macro returns no value for a bucket with no readings and no earlier value to interpolate from, which the plugin renders as a gap. This normally only happens at the very start of a series.
Learn more
- Real-Time API — the API the plugin queries, its data structure and filtering rules
- Nexalis Macros — what
@nexalis/fetch_bucketized,@nexalis/fetch_trapezoidal_averagesand@nexalis/scaledo - Common Errors — API-level errors and their causes