Wiren Board Cloud/en
Overview
Wiren Board Cloud is a remote administration service for automation systems built on Wiren Board controllers. Detailed feature description
What the cloud can do:
- open the controller web interface from anywhere in the world — no public IP or port forwarding required;
- SSH terminal and file manager right in your browser;
- open web interfaces of services running on the controller: Home Assistant, Node-RED, Zigbee2MQTT and others;
- collect controller metrics and build graphs in cloud Grafana;
- send notifications to Telegram, Discord and email when a metric in Grafana goes out of bounds;
- share controller access with other people — via organizations and roles;
- download a controller diagnostics archive in a couple of clicks.
Works on Wiren Board 6 controllers and newer. The interface is available in Russian and English.
Report bugs and send suggestions to the support portal. Attach a diagnostics archive to your problem report — you can download it right from the cloud.
Useful links:
- https://status.wirenboard.cloud — cloud status page and incident announcements;
- https://wirenboard.cloud/api/v1/docs/swagger/ — cloud REST API documentation (Swagger).
Editions
Wiren Board Cloud comes in two editions:
- https://wirenboard.cloud — the public cloud. Free, with no limit on the number of controllers.
- On-Premise — the same service on your own server. Free for up to 100 controllers per instance; a paid version is planned for fleets of hundreds and thousands of controllers.
Always use the latest On-Premise releases — they contain security fixes. Watch for new versions in the changelog and update your installation regularly.
Demo account
You can explore the cloud without registration or a controller: on the sign-in page click Demo — a read-only account with real controllers will open. Learn more on the demo page.
Quick start
Step 1. Create an account

- Open https://wirenboard.cloud and click Sign up.
- Enter your email and a password — at least 10 characters, not all digits.
- Confirm your email via the link in the message (valid for 24 hours). Messages come from
info@wirenboard.com— check your Spam folder if there is no message.
Sign-in is by email and password only; there are no third-party logins (Google etc.). An organization named after your email is created together with the account: controllers in the cloud always belong to an organization (more details).
Step 2. Check the agent on the controller
The wb-cloud-agent agent must be installed on the controller. It is preinstalled in software releases wb-2407 and newer (how to check the release on your controller).
On releases older than wb-2407 (for example, wb-2207) install the agent manually:
apt update; apt install wb-cloud-agent
Step 3. Add the controller to the cloud

By default the controller is not linked to the cloud:
- Open the controller web interface: Settings → System → the link in the Cloud status section.
- The add-controller page will open; if you are not signed in to the cloud yet, the sign-in page appears first. Confirm adding.
The same link is available in the console — connect over SSH and run wb-cloud-agent:
# wb-cloud-agent
| Provider | Controller Url / Activation Url |
|------------------|----------------------------------------------------|
| wirenboard.cloud | https://wirenboard.cloud/controllers?add=3d5...790 |
The link is valid for 4 hours and changes every time the agent or the controller restarts. If it does not work — get a fresh one.
The command shows the state with a delay: the agent polls the cloud every 10 seconds. After linking or unlinking, wait a few seconds.
Step 4. Done
The controller appears in the list with the Online status. The main buttons on its page — Web interface, SSH & Files, Grafana, Services — are described in Accessing the controller via the cloud.
There is no limit on the number of controllers in the public cloud.
The organization link is stored in the cloud, and authorization uses a hardware key that survives a factory reset — after a reset the controller will reconnect on its own. Before selling or handing over a controller, delete it from your cloud — see Disconnecting the controller from the cloud.
How it works
The wb-cloud-agent agent runs on the controller. It connects to the cloud, receives settings from it and starts three systemd services (for the public cloud):
wb-cloud-agent@wirenboard.cloud— cloud connectivity: status, commands from your account;wb-cloud-agent-frpc@wirenboard.cloud— tunnels for the web interface, terminal and services;wb-cloud-agent-metrics@wirenboard.cloud— metrics reporting for Grafana.
Data is transferred over secure channels. The controller is authorized by a key stored in the ATECCx08 hardware crypto chip; it cannot be copied or forged.
More about the architecture — in our talk Our own cloud, the new device configurator and other Wiren Board software news (in Russian).
Ports
This section is about network ports between the controller and the cloud — the user never works with them directly. These are not the local ports of controller services that you specify when adding a service.
No port forwarding or public IP is needed — all connections are outgoing from the controller:
- the agent talks to
https://agent.wirenboard.cloud; - tunnels — a single TLS connection to
tunnels.wirenboard.cloud:7105; - metrics go to
https://timescale.wirenboard.cloud.
The controller can sit behind NAT. No cloud ports are opened to the outside — tunnel ports exist only inside the cloud infrastructure.
wb-cloud-agent command reference
Full help: wb-cloud-agent -h.
| Command | What it does |
|---|---|
wb-cloud-agent |
Shows the provider table with a link to the controller page (if linked) or an activation link |
wb-cloud-agent add-provider <URL> |
Adds a cloud (provider) and starts its services. For the public cloud: add-provider https://wirenboard.cloud
|
wb-cloud-agent del-provider <name> |
Stops the cloud services and removes its settings from the controller. Accepts a name (wirenboard.cloud) or a URL
|
wb-cloud-agent del-all-providers |
Removes all configured clouds at once |
wb-cloud-agent cloud-unbind <URL> |
Deletes the controller record on the cloud server — the controller is unlinked from the organization and reappears with a fresh activation link |
wb-cloud-agent use-on-premise <URL> |
For On-Premise: removes all providers and connects the controller to your server |
The cloud interface
Controller list
The list shows all controllers of the selected organization: status, serial number, Online since, software version, description, group.
- Online — the agent is in touch; Problem — no connection, with the time since the controller became unavailable.
- There is a search by serial number, version, description and group, a group filter, and a map of all controllers.
- A button in the header exports the list to CSV or XLSX.
- An empty list shows the How to connect the controller hint.

Controller groups
Groups let you organize controllers by site or customer. It is a tree up to 3 levels deep; groups belong to the organization.
- Create, rename and delete groups in the controller list.
- Move a controller to a group from its page or in bulk: checkboxes → Move → Move to another group.
- When a group is deleted, its controllers stay in the organization without a group.
- The group filter also includes nested subgroups.
Controller page

On the controller page:
- access buttons: Web interface, SSH & Files, Grafana, buttons of added services, Services (settings);
- editable Description and Group;
- the Metrics reporting switch (see Metrics and cloud Grafana);
- name–value notes (Add a note, up to 100) — site address, contacts, contract number;
- location on the map — set manually or via geosearch;
- four graphs for the last hour: 15-minute load average (load15), free RAM, free space in
/and/mnt/data(with metrics enabled, refreshed every minute); - at the bottom — Last agent contact and Last metrics contact with the time of the last communication.
Diagnostics from the cloud

You can get a diagnostics archive right from your account, without SSH:
- On the controller page click Request a diagnostic.
- Wait for collection to finish and click Download diagnostics — a zip archive will download.
- Attach the archive to your request on the support portal.
Requires agent 1.5.0 or newer and the controller being online.

An organization is a "folder" with controllers and a list of people who can access them. A controller belongs to exactly one organization; a user can be a member of several.
- A personal organization named after your email is created at registration. It can be renamed.
- The Create an organization button in the organization list creates a new one; the creator becomes its owner. The number of organizations is unlimited.
- Organization settings — the gear button in the controller list header (visible to admins and the owner).
Roles
| Role | What they can do |
|---|---|
| User | Sees organization members; edits controllers, opens their web interfaces, terminal and Grafana, deletes controllers |
| Admin | All of the above + invites and removes members, transfers controllers, enables mandatory 2FA for the organization |
| Owner | All of the above + assigns and removes admins, renames and deletes the organization |
There is one owner, and ownership cannot be transferred via the interface — instead, transfer the controllers to the new owner's organization, see Transferring controllers. The service role Demo is read-only (used by the demo account).
Inviting members

- On the organization page click Invite and enter an email.
- An email with a link will arrive — the link is single-use and valid for 5 days.
- If the invitee has no account, they register via the same link and join the organization right away.
The invitee gets the User role; the owner can change roles.
Mandatory two-factor authentication
The owner or an admin enables the 2FA requirement with the Two-factor authentication button on the organization page (the person enabling it must have 2FA enabled themselves; enabling and disabling the requirement is confirmed with a code). Members without 2FA will not be able to work with the organization until they enable it — see Account security.
Leaving and deleting an organization
- Leave organization is available to any member except the owner.
- Delete organization is available only to the owner and only when no controllers and no other members remain. With 2FA enabled, deletion is confirmed with a code.
Account security

All security settings live in the Security section — it opens from the menu under the user icon in the top right corner.
Changing your password and email
- Password change: enter the old and the new password; with 2FA enabled — a code as well. After the change, all sessions on other devices are terminated.
- Email settings: the new email is confirmed via a link from the message (valid for 15 minutes); with 2FA enabled — a code as well.
- Forgot your password — use Forgot password? on the sign-in page. Note: a password reset via the emailed link does not terminate open sessions — if you suspect someone else is using the account, terminate them manually in Security.
After dozens of failed sign-in attempts, sign-in is blocked for 1 hour. If you forgot the password — recover it via the link, do not brute-force it.
Two-factor authentication
The cloud supports two-factor authentication (2FA) with one-time codes from an authenticator app (Google Authenticator, 2FAS, Authy, Microsoft Authenticator etc.).
How to enable:
- In the Security section click Enable in the Two-factor authentication block.
- Scan the QR code with the app. No camera — enter the text code shown under the QR into the app.
- Enter the received code and click Confirm. Sessions on other devices will be terminated.
- Save the 6 single-use recovery codes (the Download button).
Store the recovery codes in a safe place and never share them. If you lose the device with the authenticator app, these codes will be the only way to sign in to your account.
From now on, signing in requires the app code in addition to the password.
Lost the device — click Enter 2FA recovery code on the sign-in page. After signing in that way, re-enable 2FA so you do not run out of codes.
More facts:
- 2FA is disabled with the Disable button, confirmed with a code;
- an email is sent when 2FA is enabled or disabled;
- sensitive actions (changing the password or email, deleting and transferring controllers, deleting an organization, changing the organization's mandatory 2FA) ask for the code again; the confirmation is valid for 3 minutes;
- the owner or an admin can make 2FA mandatory for the organization — see above.
Active sessions

The Active sessions block shows which devices are signed in to your account and lets you terminate extra ones — for example, after signing in from someone else's computer.
For each session you can see: the device and browser, location and IP address, last activity time. Your current session is labeled Current; clicking a row expands the details (OS, exact sign-in time).
- Terminate — signs out the selected device.
- Terminate all except current — ends all other sessions at once.
Sessions are terminated automatically when you change the password via the Security section and when you enable 2FA. If a device has not been used to sign in for 3 weeks, its session expires on its own.
The location is determined by IP address approximately. With a VPN or mobile internet it may show the country and city of the exit point, not the actual one.
If you see an unfamiliar session — click Terminate all except current, change the password and enable two-factor authentication.
Transferring controllers to another organization
You can transfer one or several controllers (up to 20 at a time) to another organization.
A transfer can be started in two ways:
- On the controller page — the Transfer to another organization button.
- In the controller list — select controllers with checkboxes and click Move.
A window opens where you choose the transfer type. If you have 2FA enabled, transfer operations are confirmed with a code.
Moving within your organizations

You need admin or owner rights in both organizations. Choose Move within your organizations and the target organization — the controllers are moved immediately (the operation fails if a controller is already part of another transfer request).
Transferring to someone else's organization

No access to the target organization — choose Transfer to another organization and enter the email of a user registered in the cloud. A transfer request is created and the user receives an email with a link.
The recipient opens the link, sees the list of controllers being transferred, picks an organization where they are the owner or an admin, and clicks Move (with 2FA — a code).

While the request is active, the listed controllers cannot be transferred or deleted. The request can be cancelled — with the Cancel transfer button on the controller page or in the list.
The request completes when:
- the recipient accepts the transfer;
- you cancel the request;
- the request expires — after 2 hours.
Cancelling a request cancels the transfer for all controllers in it. A request can only be sent to a user already registered in the cloud.
What happens to the data during a transfer
- The group is always reset — groups belong to the source organization.
- Metrics history is not transferred: the new organization's graphs start from the moment of the transfer; the old data remains visible only to the previous organization.
- The Clear the description, notes, and coordinates of the controller in the cloud checkbox deletes the description, coordinates and notes. It also removes the added services — their buttons and tunnels; the programs themselves keep running on the controller, and the new owner can add them to the cloud again.
The controller is linked to someone else's organization
You have physical access to the controller but no access to the organization it is linked to (for example, it was bought second-hand):
- Unlink the controller:
wb-cloud-agent cloud-unbind https://wirenboard.cloud(see Disconnecting the controller from the cloud). If unlinking fails — update the controller. - Link it to your organization via a fresh activation link — see Quick start.
Accessing the controller via the cloud
Controller web interface
The Web interface button on the controller page opens the standard controller web interface at:
https://XXXXXXXX.http.wirenboard.cloud, where XXXXXXXX is the controller serial number.
Via the cloud the interface is fully functional, including controller software updates. How to use the interface itself — see Wiren Board Web Interface.
You cannot factory-reset the controller from the cloud — the connection to the controller would likely be lost.
SSH & Files

The SSH & Files button opens the controller terminal right in the browser — no SSH client needed on your computer.
- In the sign-in form enter the controller username and password; the Set default credentials button fills in the factory
root/wirenboard. - Signing in with a private key is supported (RSA, ECDSA, Ed25519; passphrase optional). If two-factor authentication is configured for SSH on the controller, the terminal will ask for a one-time code.
- On a phone the terminal is easy to use thanks to the on-screen panel with CTRL/ALT keys and arrows.
Next to the terminal is the File manager block: browse directories, download and upload files, delete files and folders.
File manager limits:
- uploading to the controller — files up to 350 MB; if a file with the same name exists, it is overwritten (with a warning);
- downloading from the controller — no file size limit; if the connection drops, the browser can resume the download.
Accessing web interfaces of controller services

A service is a program with a web interface running on the controller: Home Assistant, Node-RED, Zigbee2MQTT or your own software. It can be opened right from the cloud — from any device where you are signed in and a member of the controller's organization.
A service is defined by the port it listens on. An added service gets its own button on the controller page and its own address:
where XXXXXXXX is the controller serial number and PPPP is the service port on the controller.
Adding a service

- On the controller page click Services.
- Pick a popular service from the catalog — the hint fills in the port and name. For your own service enter the port manually (it is in the service settings on the controller).
- The name is optional — it is shown on the button; without it the button shows the port number.
- Save — a service button appears on the controller page.
The port and name can be changed at any time: the connection reconfigures itself, the link stays the same.
Limitations:
- up to 20 services per controller;
- the service must run on the controller itself and listen on
127.0.0.1(localhost). A program listening only on the controller's external network interface will not open via the cloud; - system service ports cannot be used — the cloud will reject them: 22 (SSH), 80 (taken by the built-in web interface tunnel), 1883, 8883, 18883–18886 (MQTT), 6720 (knxd);
- only web interfaces can be opened this way — things that open in a browser. You cannot connect to the controller over MQTT, Modbus TCP or with a regular SSH client like this.
You can bookmark a service link: while you are signed in to the cloud, it opens the service right away; otherwise the cloud asks you to sign in and returns you to the same page.
When a new service is opened for the first time, or its port is changed, or it is deleted, the controller's cloud connection briefly restarts — open tabs of this controller will be interrupted for a few seconds; refresh the page.
Who has access
Only signed-in members of the controller's organization — an outsider following the link will see nothing.
On opening, the cloud gives the browser a 15-minute key and renews it automatically while the tab is open. After a brief connection loss the page reconnects on its own.
Notes on specific services
Access from the Home Assistant mobile app is not supported; open HA in the phone browser instead — you can pin the link to the home screen for quick access.
Home Assistant. By default it does not trust requests coming through the cloud and responds with 400: Bad Request. Add to its configuration.yaml on the controller and restart Home Assistant:
http: use_x_forwarded_for: true trusted_proxies: - 127.0.0.1 - ::1 - 172.16.0.0/12
Node-RED and most other services work via the cloud right away, no configuration needed.
Removing a service
Remove the service in the same Services window: the button disappears, the tunnel closes. The program itself keeps running on the controller.
Proxying arbitrary web interfaces on the controller
In most cases use the standard Services mechanism — the method below is only needed when an application must be "mounted" into the controller web interface under a sub-path (URI) rather than opened on a separate port.
In the controller's nginx you can configure a proxy for an arbitrary (previously non-existent) URI — this works with most applications.
Instructions with an example
Example: access the Zigbee2MQTT web interface under the URI "z2m". The Zigbee2MQTT interface is enabled on port 8081 (check the port in the service settings).
- Create a proxy configuration file:
mcedit /etc/nginx/includes/default.wb.d/z2m.conf
- Add a location entry:
location ~ ^/z2m/(.*)$ { set $upstream_app 127.0.0.1; set $upstream_port 8081; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port/$1$is_args$args; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; }
- After saving, restart the server and check its status:
systemctl restart nginx; systemctl status nginx
- To test locally, open
http://ip-address/z2m/, where ip-address is the controller address. The trailing slash is mandatory. - Via the cloud:
https://XXXXXXXX.http.wirenboard.cloud/z2m/, where XXXXXXXX is the controller serial number.
More on configuring other services — in the nginx documentation.
Disconnecting the controller from the cloud
There are three ways, and they do different things:
| Method | When to use | What happens |
|---|---|---|
| Deletion from your account | The standard way: the controller is no longer needed in the cloud, or you are selling or handing it over | The controller disappears from the organization; its description, notes and services are cleared. The agent on the controller stops all of its services and removes the provider settings — the controller stops talking to the cloud entirely. To connect it again, run on the controller:wb-cloud-agent add-provider https://wirenboard.cloud
|
cloud-unbind over ssh on the controller |
You have physical access to the controller but no access to the cloud account (for example, a second-hand controller linked to someone else's organization) | The controller record in the cloud is deleted — the link to the previous organization is severed. The agent keeps running and in a few seconds receives a new activation link. The controller is not linked to any organization and is visible to no one — use the link to add it to your own organization |
del-provider over ssh on the controller |
You want the controller to stop contacting the cloud entirely | The agent stops all of its services and removes the provider settings. The link in the cloud remains — the controller will show as unavailable until you delete it from your account |
Deletion from your account: on the controller page click Delete controller and enter its serial number (with 2FA enabled — a code as well). While the controller has an active transfer request, deletion is unavailable.
Commands on the controller (over SSH).
Unlink from the organization:
wb-cloud-agent cloud-unbind https://wirenboard.cloud
Disconnect from the cloud entirely:
wb-cloud-agent del-provider wirenboard.cloud
Restore the factory state:
wb-cloud-agent add-provider https://wirenboard.cloud
Do not run these commands via the cloud terminal: both of them break the cloud connection, the terminal will close mid-way, and after del-provider the controller can only be brought back with add-provider over regular SSH.
Metrics and cloud Grafana
The cloud collects controller metrics (MQTT channel values) and shows them in the built-in Grafana: a ready-made dashboard, your own graphs, alerts.
Enabling metrics reporting
Metrics reporting requires the wb-cloud-agent package version 1.7.0 or newer — available since release wb-2507. If the agent is older, the cloud shows a banner with the update command on the controller page.
To update only the agent, without updating all system packages, run on the controller:
apt update; apt install --only-upgrade wb-cloud-agent


Reporting is controlled by the Metrics reporting switch (Enabled/Disabled) on the controller page. After updating the agent or enabling the option, wait up to half an hour — the agent will receive the settings and start the reporting service; after that, metrics are sent every 2 minutes.
Metrics are stored in the cloud for 30 to 32 days.
To disable — the same switch: the agent will stop the reporting service on the controller.
Which topics are sent to the cloud
Only the channels (topics) stored in the local wb-mqtt-db database reach the cloud. Disable history recording for a channel in the controller web interface — it will stop going to the cloud too (less traffic).
Keep the channels used by the cloud dashboards enabled — otherwise their panels will be empty (No data). A small set of system topics (serial number, firmware, total memory and disk sizes) is sent regardless of the history settings — as long as Metrics reporting is enabled.
If the controller was offline, data is not lost: after the connection is restored the agent uploads everything the local wb-mqtt-db history managed to store during the downtime. How much can be recovered depends on the wb-mqtt-db storage settings and on the metrics flow: the more channels are recorded, the shorter the period the local history covers. The upload runs in batches — up to a few thousand records per minute, so after a long downtime the Grafana graphs fill in gradually.
Using Grafana

- On the controller page click Grafana.
- You are signed in automatically, and our Controller Metrics dashboard opens with this controller already selected.
- Dashboard panels: uptime, CPU and board temperatures, hardware revision, disk space, RAM, load, and a table of recent MQTT data (the topic dropdown). The controller dropdown at the top switches the controller; the default time range is 6 hours.
- The organization is switched in the top left corner of Grafana — only your organizations are available.
Permissions depend on your cloud role: the owner and admins create dashboards and alert rules, users can only view.
If there are no metrics (No data):
- the controller has not sent them yet after an agent update or after enabling the option;
- metrics reporting is disabled on the controller page;
- the selected time range has no metrics.
Do not edit the default dashboard. It is managed by our team and is periodically updated from the cloud — your changes will be lost on update. To build your own graphs, copy the dashboard or create one from scratch.
How it works: the controller, TimescaleDB and cloud Grafana
The metrics collector script ships with the wb-cloud-agent package. The agent receives only settings from the cloud (ingest address, intervals, system topics) and stores them in metrics_collector.conf; the ready-to-run script is assembled from the settings and the package template. Both files live in the provider directory:
/var/lib/wb-cloud-agent/providers/wirenboard.cloud/metrics_collector.conf /var/lib/wb-cloud-agent/providers/wirenboard.cloud/metrics_collector.py
The script is run by the wb-cloud-agent-metrics@wirenboard.cloud service; it reads data from wb-mqtt-db and the local MQTT broker and every 2 minutes sends it over HTTPS to timescale.wirenboard.cloud — into TimescaleDB, from which Grafana reads it.
Do not edit metrics_collector.py by hand: the agent rebuilds it on every start and whenever the settings change — your edits will be overwritten.
Views for queries
The metrics data is available through views — virtual tables that you pick in the Table field of the Query Builder or reference in SQL queries.
mqtt_metrics_readable is the main view for user dashboards:
| Field | What it contains |
|---|---|
time |
Metric time |
host |
Controller serial number |
topic |
MQTT topic, e.g. /devices/hwmon/controls/CPU Temperature
|
value |
The raw value as text |
value_numeric |
The same value as a number, when it could be converted (otherwise empty) |
There are also helper views so you do not have to write extra conditions by hand.
mqtt_metrics_numeric_readable — numeric values only, convenient for graphs: no value_numeric IS NOT NULL condition needed.
| Field | What it contains |
|---|---|
time |
Metric time |
host |
Controller serial number |
topic |
MQTT topic |
value |
The value — already numeric |
mqtt_metrics_topics_readable — a ready way to see which topics a controller has.
| Field | What it contains |
|---|---|
host |
Controller serial number |
topic |
MQTT topic |
first_seen |
When the topic first appeared on the controller |
org_controllers — the list of controllers available to you, handy for your dashboard variables.
| Field | What it contains |
|---|---|
host |
Controller serial number |
All views enforce per-organization access control: you only see data of controllers from organizations available to you. A query with someone else's serial number returns nothing — this applies to all dashboards, the Query Builder and SQL.
Creating a dashboard
For simple graphs you do not need SQL: use the mqtt_metrics_readable view and the Query Builder mode.
Copying the default dashboard
The easiest way is to copy the default dashboard and modify the copy — it keeps the controller dropdown that switches the controller for all panels at once.
- Open the default dashboard (the Grafana button on the controller page).
- Click Edit in the top right corner, then Save dashboard → Save as copy → Save. Your copy appears and can be freely modified.
- Add your own panels to the copy (Add → Visualization). To make a panel follow the dropdown, use the
${controller}variable instead of a specific serial number in the filter. In Code mode it looks like this:WHERE host = '${controller}'
- In Builder mode set the
hostfilter to${controller}.
Example: CPU temperature graph without SQL

Step-by-step instructions
- Open Dashboards → New → New dashboard.
- Click Add visualization.
- Select the timescaledb data source.
- In the query editor select the Builder mode.
- In the Format field select Time series.
- In the Table field select
mqtt_metrics_readable. - Select Time series as the visualization.
- Add filters, enabling them with the Filter checkbox first:
host= the controller serial number;topic=/devices/hwmon/controls/CPU Temperature;value_numericis not null.time→ the Macros operator → timeFilter. This filter is mandatory: without it Grafana may pick old rows outside the selected range and show the Data outside time range error.
- For the value, in Data operations select Column
value_numericwith theAVGaggregate (average). - For time, add another Data operations entry: select the
$__timemacro with Columntime. It converts the time column into the format Grafana uses for the X axis. - Enable Group and select
timein Group by column. - Enable Order and sort by
timein ASC order. Clear the Limit field. - In the panel's Standard options (on the right) set the Unit to Temperature Celsius (°C).
- In Panel options set the Title, e.g. CPU Temperature (°C).
- Click Save dashboard, enter a Title and save with Save.
This graph shows the CPU temperature over time. For other numeric MQTT topics the steps are the same — only the topic filter changes.
To skip the value_numeric is not null filter, select the mqtt_metrics_numeric_readable view in the Table field — it contains only numeric values, and the number itself is in the value field.

Example: free RAM stat tile without SQL

Step-by-step instructions
- Add another panel to the dashboard with Add → Visualization.
- Select the Stat visualization.
- Select the timescaledb data source.
- In the query editor select the Builder mode.
- In the Format field select Table.
- In the Table field select
mqtt_metrics_readable. - Add filters, enabling them with the Filter checkbox first:
host= the controller serial number;topic=/devices/metrics/controls/ram_available;value_numericis not null.time→ the Macros operator → timeFilter.
- For the value, in Data operations select Column
value_numeric. - Enable Order and sort by
timein DESC order. Set Limit to 1 so the tile shows only the latest value. - In the panel's Value options (on the right) select Calculation Last.
- In Panel options set the Title, e.g. RAM available MiB.
- Click Save dashboard and save with Save.
For text values use the value column. For example, the /devices/system/controls/Current uptime topic stores the uptime as a string, and /devices/system/controls/HW Revision — the hardware revision.

Useful SQL queries (advanced)
SQL can be used in Grafana Explore or in a panel when the Query Builder is not enough.
SQL query examples
Topics of a specific controller for the last 24 hours with row counts:
SELECT topic, count(*) AS rows_24h, max(time) AS latest FROM mqtt_metrics_readable WHERE host = '<put the controller serial number here>' AND time > now() - interval '24 hours' GROUP BY topic ORDER BY rows_24h DESC, topic;
If you just need the list of a controller's topics, without row counts, use the mqtt_metrics_topics_readable view:
SELECT topic FROM mqtt_metrics_topics_readable WHERE host = '<put the controller serial number here>' ORDER BY topic;
Latest values of several controller topics:
SELECT DISTINCT ON (topic) topic, time, value FROM mqtt_metrics_readable WHERE host = '<put the controller serial number here>' AND topic IN ( '/devices/system/controls/HW Revision', '/devices/system/controls/Release name', '/devices/system/controls/Current uptime', '/devices/metrics/controls/ram_available', '/devices/metrics/controls/ram_total' ) AND time > now() - interval '24 hours' ORDER BY topic, time DESC;
A CPU temperature graph for a Grafana panel in Code mode:
SELECT AVG(value_numeric), $__time("time") FROM mqtt_metrics_readable WHERE ( host = '<put the controller serial number here>' AND topic = '/devices/hwmon/controls/CPU Temperature' AND value_numeric IS NOT NULL AND $__timeFilter("time") ) GROUP BY "time" ORDER BY "time" ASC
Exporting data to CSV

- Open the Query inspector.
- Go to the Data tab.
- Click Download CSV to export the query result to a file.
Getting help from AI
You can ask an AI for a complex dashboard:
- Export the controller data to CSV (see above) and attach the list of its topics — the
mqtt_metrics_topics_readablequery from Useful SQL queries. - Describe what you need: panels, period, units, filters, visualization type.
For example: "Generate a Grafana dashboard JSON for TimescaleDB. Data source — timescaledb, table — mqtt_metrics_readable. I need graphs of CPU temperature, free RAM and free space on /mnt/data for the selected controller".
Check the result after each iteration and refine the prompt — a few iterations are usually enough.
Importing a dashboard
To import a dashboard .json file:
- Open Dashboards.
- In the top right corner click New → Import.
- Select the file to import.
Event notifications
Grafana watches the metrics itself and sends a message when a value goes out of bounds: the CPU overheated, power was lost, an input switched on, disk space is running out. Delivery channels — email, Telegram, Discord, webhooks and a dozen more services (full list).
Configuration lives in the Alerting section of cloud Grafana. Everything you create belongs to the organization; the owner and admins can create and edit rules, other members see them read-only.
You need two things:
- A contact point — where to send the message.
- A rule (Alert rule) — what to check and when to fire.
A single contact point can hold several channels — one rule will send the message to all of them.
Step 1. Where to send

- Open Alerting → Contact points → + Create contact point.
- In the Name field enter a clear name, e.g. "My Telegram".
- In the Integration field select the service and fill in its fields — how to get the credentials for each is described below:
- Telegram — BOT API Token and Chat ID;
- Discord — Webhook URL;
- Email — recipient addresses.
- Click Test — the message arrives immediately, even before a rule exists. This is the quickest way to check the channel works.
- To send to several places at once, click + Add contact point integration and add another service to the same contact point.
- Click Save contact point.
Telegram: getting the token and Chat ID
You create your bot once; it then works for all your rules.
Instructions
- Open the @BotFather bot in Telegram and click Open, then + Create a New Bot.
- Choose a display name (anything) and a username — it must end with
bot, e.g.my_wb_alerts_bot. - Click Create, then Copy — a string like
1234567890:AAFxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxis copied. This is the BOT API Token — paste it into the field of the same name in Grafana. - Find your bot in the Telegram search, open the chat and click Start. This step is mandatory: until you message the bot first, Telegram forbids it from messaging you.
- Get the Chat ID: message the @userinfobot bot; it replies with an Id like
846068007. That is the Chat ID for direct messages — paste it into the field of the same name in Grafana.
To receive notifications in a group instead of direct messages:
- Add your bot to the group as a member.
- Send any message to the group and forward it to @userinfobot — it will show the group Id.
Discord: getting the Webhook URL
Instructions
- You need the Manage Webhooks permission on the server — the server owner has it.
- Hover over the channel, click the gear Edit Channel → Integrations → Webhooks → New Webhook.
- Set a name — it will be shown as the message author, e.g. "Wiren Board Cloud".
- Make sure the right channel is selected and click Copy Webhook URL.
- You get a link like
https://discord.com/api/webhooks/1234567890/AbCdEf...— paste it into the Webhook URL field in Grafana.
A Webhook URL is equivalent to a password: whoever has it can post to your channel as the webhook. Do not publish it. If it leaks — delete the webhook with the same button; the old link stops working immediately.
Email: what to fill in
- In the Addresses field enter the recipients; separators — newline, comma or semicolon.
- Nothing else to configure — the mail server is already set up on the cloud side.
Messages come from alerts@wirenboard.com. If there is no message — check the Spam folder and whitelist the sender so the next ones arrive in the Inbox.
Step 2. What to check


- Open Alerting → Alert rules → + New alert rule.
- In the Name field enter a clear name, e.g. "Controller overheating".
- In the Define query and alert condition block select the timescaledb data source and build the query in Builder mode — just like for dashboard panels, no SQL needed:
- In the Format field select Time series, in the Table field —
mqtt_metrics_readable. - Add filters, enabling them with the Filter checkbox:
host= the controller serial number;topic=/devices/hwmon/controls/CPU Temperature;value_numericis not null;time→ the Macros operator → timeFilter. - In Data operations select Column
value_numeric, no aggregate needed — the condition below takes the latest value itself. Add a second Data operations entry: the$__timemacro with Columntime. - Enable Order by
timein ASC order, clear the Limit field.
- In the Format field select Time series, in the Table field —
- Below, in Alert condition: in WHEN select the Last function — it takes the latest value, and in OF QUERY set the condition, e.g. IS ABOVE 55.
- In Add folder and labels pick a folder (create one if needed), in Set evaluation behavior set the Evaluation group and interval — how often to check (create a group if needed). The minimum is 30 seconds.
- Pending period — how long the condition must hold before the message is sent. Set 0s to be notified immediately.
- In Configure notifications select the contact point from step 1.
- Click Save at the very bottom of the page.
SQL query variant (Code mode)
SELECT time, value_numeric AS value FROM mqtt_metrics_readable WHERE host = '<put the controller serial number here>' AND topic = '/devices/hwmon/controls/CPU Temperature' AND value_numeric IS NOT NULL AND $__timeFilter(time) ORDER BY time
The rule appears in the list. When the condition is met (the temperature rises above 55 degrees), the rule switches to Firing and the message is sent; when the value returns to normal, a recovery notification arrives.
This is the bare minimum; all rule settings are covered in the Grafana documentation: Configure Grafana-managed alert rules.
Example: alert on a switch
The same approach works with any 0/1 channel: an input, a relay, a discrete output, a wb-rules flag. Build the rule exactly as in step 2, except:
- in the
topicfilter specify your channel, e.g./devices/wb-gpio/controls/A1_OUT; - set the condition to IS ABOVE 0.5 — anything non-zero counts as on.
Toggle the channel in the controller web interface — the message arrives within 1–3 minutes.
Discrete channels are recorded on change, not on schedule. So use a wide time range in the query (several hours), otherwise after a toggle the rule quickly returns to Normal simply because no new rows arrive. For the same reason set Alert state if no data → Normal in the rule: no rows is not an emergency here. More on the No data and Error states — in the Grafana documentation: No data and error states.
How soon the message arrives
In practice — within 1–3 minutes of the event. The delay is a sum of:
- metrics reporting from the controller — every 2 minutes (the interval is not adjustable);
- rule evaluation — every Evaluation interval (minimum 30 seconds);
- the Pending period, if set;
- Group wait — 30 seconds to gather simultaneous firings into one message.
More on the evaluation cycle — Alert rule evaluation.
How often messages repeat
Grafana groups alerts and spaces messages out in time. Three settings in Alerting → Notification policies (Timing options):
- Group wait — the pause before the first message of a group; gathers simultaneous firings into one. Ours is 30 seconds.
- Group interval — the pause before a message about changes in the group. The main frequency limiter: a flapping rule with a 5-minute interval produces 12 messages per hour instead of 60. Ours is 5 minutes.
- Repeat interval — the pause before a reminder when the alert is still firing. Ours is 4 hours.
You can change these both for the whole organization (Notification policies) and per rule (Muting, grouping and timings).
Do not make the intervals too small. A flapping rule with a one-minute interval will flood you with messages.
A group is a set of alerts with identical labels. The cloud default grouping is: one rule = one group = one message. So a rule that returned a hundred rows sends one message, not a hundred.
More on how this works — in the Grafana documentation: Group alert notifications and Configure notification policies.
Customizing the message text
The standard Grafana message is technical: rule name, labels, values. You can extend or replace it.
The simple way — the Summary and Description fields in the rule's Configure notification message block: the text goes into the message in all channels. Placeholders work: CPU temperature has risen to {{ $values.B }} °C — the number that triggered the condition (full placeholder list).
For a fully custom format — a template: Alerting → Contact points → Notification Templates → + Add notification template group (you can start from the examples, Add example) → Save. Then attach it in the contact point: expand the integration's Optional settings and in the Message field (for Email — optionally Subject too) enter {{ template "template_name" . }}. Templates use the Go template language (Customize notifications).
A template applies at the contact point level: it changes the look of all messages delivered through it, from all rules.
Limitations
- up to 20 rules per organization (and up to 20 dashboards);
- metrics reporting from the controller — once every 2 minutes; the interval cannot be changed from the cloud;
- rule evaluation — at most once every 30 seconds;
- messages are grouped per rule: a rule that returned a hundred rows sends one message, not a hundred;
- a rule must return no more than 100 rows. Do not query all controller topics at once — filter by
topic, or the rule will hit the limit; - the firing history is stored for 30 days;
- your own webhook — HTTPS only (any port). An
http://address is rejected by the cloud — you get403 Forbidden: over http the secret webhook address and the notification contents would travel in cleartext; - the cloud cannot reach your local network — the webhook must be accessible from the internet.
If the message does not arrive
- Click Test in the contact point. Arrived — the channel is fine, the problem is in the rule; did not arrive — read the error text shown right in the window.
- Open the rule and check its state. Normal — the condition was not met, check the threshold. No data — the query returned nothing: check the serial number, the topic and that metrics are flowing at all. Error — a query error, the text is next to it.
- Make sure the rule uses your contact point, not the default one.
- What the typical errors mean:
401 Unauthorizedfrom Telegram — wrong bot token;Unknown Webhookfrom Discord — wrong or deleted Webhook URL;403 Forbiddenfrom a webhook — anhttp://address instead ofhttps://, or it points into a private network.
Troubleshooting
Start with your cloud account and the cloud status page, then move on to commands on the controller. If that does not help — send the command output and a diagnostics archive to support.
Cloud status
Open the status monitoring page:
All indicators should be green. If there is an outage — wait for recovery.
The controller shows Problem
- On the controller page check the Last agent contact line — the time of the controller's last communication with the cloud.
- Check that the controller is powered on and has internet access (see the SSH checks below).
- If the controller is online but tunnels do not open — try again in a minute: the cloud restarts the controller's tunnels automatically on failure.
No link to add the controller
If there is no activation link in the controller web interface, connect over SSH and check the providers with wb-cloud-agent:
No one provider was found— no provider configured. Add it:wb-cloud-agent add-provider https://wirenboard.cloud;No connect to: https://wirenboard.cloud— the controller has no connection to the cloud, check the internet (see below);- if the link exists but does not work — get a fresh one: the link is valid for 4 hours and changes when the agent restarts. If the controller is already linked to another organization, there is no link — unlink it first (see Disconnecting the controller from the cloud).
No metrics in Grafana
- Check that Metrics reporting is Enabled on the controller page and the agent version is at least 1.7.0 (with an older agent the cloud shows a banner with the update command).
- Wait: after enabling or updating the agent, the first data appears within half an hour; after that metrics arrive every 2 minutes.
- Check the selected time range and the
host/topicfilters; see the controller's topics in themqtt_metrics_topics_readableview. - Use
value_numericfor graphs (or themqtt_metrics_numeric_readableview),valuefor text values. - Metrics come from the local wb-mqtt-db history: if history recording is disabled for a channel, it does not reach the cloud.
- Check the reporting service on the controller:
systemctl status wb-cloud-agent-metrics@wirenboard.cloud
- If the service is crashing, check its journal and attach the output to your support request:
journalctl -u wb-cloud-agent-metrics@wirenboard.cloud -n 300 --no-pager
No connection to the cloud: checks over SSH
Use these checks when the controller does not reach the cloud — the Problem status or no activation link. One by one they rule out: no internet, broken DNS, an unreachable cloud server, a stopped agent.
Connect to the controller over SSH and run these in order.
Internet connectivity check:
ping 8.8.8.8 -c 4
Expected: successful replies. If not — check the internet connection.
DNS resolution check:
getent hosts agent.wirenboard.cloud
Expected output:
5.35.10.8 wirenboard.cloud agent.wirenboard.cloud
Empty output — the problem is DNS.
Cloud server reachability check:
ping wirenboard.cloud -c 4
Expected: successful replies from 5.35.10.8. If the internet works but the cloud server does not respond — check the cloud status.
wb-cloud-agent service check:
systemctl status wb-cloud-agent@wirenboard.cloud
Expected: active (running). If the service is stopped, start it:
systemctl enable wb-cloud-agent@wirenboard.cloud systemctl start wb-cloud-agent@wirenboard.cloud
HTTPS connection check (for Wiren Board 7 and newer):
curl --connect-timeout 45 --retry 8 --retry-delay 1 --retry-all-errors \ --cert /var/lib/wb-cloud-agent/device_bundle.crt.pem \ --engine ateccx08 \ --key ATECCx08:00:02:C0:00 \ --key-type ENG \ -w '|||{"code":"%{response_code}"}' \ https://agent.wirenboard.cloud/api-agent/v1/agent-start-up/
Expected: a response with HTTP code 200.
On Wiren Board 6 the hardware key is different — in the command above replace ATECCx08:00:02:C0:00 with ATECCx08:00:04:C0:00, otherwise the command fails.

