grafana: dashboard bundle + dev-stack integration
Some checks failed
Validate / HACS validation (push) Has been cancelled
Validate / Hassfest (push) Has been cancelled

Adds a self-contained omni-pca/grafana/ bundle (InfluxDB v2 + Grafana
with pre-provisioned datasource and dashboard) plus dev-stack wiring
so iterating against the mock or real panel is one docker-compose-up.

The dashboard has four rows plus an insights row:

  System health   AC, battery, trouble, 24h event count
  Security        area arming state, recent events table, zone trips
  Climate         thermostat temperatures, HVAC mode
  Activity        event rate by type, top toggled units
  Insights        active zone bypasses, button press log, event distribution

Color-coded event_type tags persist across panels (alarms red, restores
green, batteries orange, etc.); explicit no-purple palette per CLAUDE.md.

The bundle is portable: any HA install can use it by running grafana/
docker compose up -d and pasting ha-snippet.yaml into configuration.yaml.
For the dev stack, dev/docker-compose.yml mounts the same provisioning
files so dev and prod stay in lockstep.

Verified end-to-end against the real Our House.pca panel (192.168.1.9):
the dashboard fills with live zone trips, X-10 unit toggles, and
push-event traffic within 30s of HA bootup.
This commit is contained in:
Ryan Malloy 2026-05-17 23:43:01 -06:00
parent 9726ee36bb
commit 4ba8c2043e
11 changed files with 1101 additions and 0 deletions

View File

@ -70,6 +70,49 @@ OMNI_PCA_FIXTURE_KEY=0xC1A280B2 # or --pca-key on the command line
buttons, programs, model byte, and firmware version from the file —
everything the HA integration reads at discovery time.
## Time-series & dashboards
`docker compose up -d` also brings up **InfluxDB v2** (port 8086) and
**Grafana** (port 3000). Open Grafana at <http://localhost:3000>
(login: `admin` / `$GRAFANA_PASSWORD` from `.env`) — the **Omni Pro II
— Panel Overview** dashboard loads automatically, pre-provisioned from
[`../grafana/`](../grafana/), the shipping bundle.
To wire HA → InfluxDB, append this block to `ha-config/configuration.yaml`
(the directory is gitignored because it contains HA auth/state; the
block lives in `../grafana/ha-snippet.yaml` for production users):
```yaml
influxdb:
api_version: 2
host: influxdb
port: 8086
ssl: false
verify_ssl: false
token: dev-token-omnipca-9472-fixed-for-dev-stack
organization: omni-pca
bucket: ha
precision: s
tags_attributes: [event_type, event_class]
include:
domains: [alarm_control_panel, binary_sensor, climate, event, light, sensor, switch]
entity_globs: ["*omni*"]
```
Restart HA (`docker compose restart homeassistant`) after editing.
Within 30 seconds, panels start populating with live data.
The dashboard JSON in `../grafana/provisioning/dashboards/` is the
source of truth; edits in the Grafana UI don't persist (provisioned
dashboards are read-only). Iterate by editing the JSON and running
`docker compose restart grafana` — the provisioner picks up changes
within ~30s.
To exercise dashboard panels against the mock, trigger HA actions
(arm an area, toggle a light): the mock pushes the resulting
`SystemEvent` back to HA, which ships it to InfluxDB, which Grafana
queries. Each step takes <1s.
## Notes
- The HA container mounts `../custom_components/omni_pca/` read-only, so

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

View File

@ -102,6 +102,74 @@ services:
pip install --quiet --no-deps --upgrade /opt/omni-pca-src
exec /init
# InfluxDB v2 + Grafana stack — kept inline rather than `extends:`-ing
# ../grafana/docker-compose.yml so this file stays self-contained and
# the named volumes get scoped to this compose project. The bundle
# compose stays the canonical ship-to-users version; we share its
# provisioning files via the volume mount on the grafana service.
influxdb:
image: influxdb:2.7-alpine
container_name: omni-pca-dev-influxdb
restart: unless-stopped
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUX_USERNAME:-admin}
DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUX_PASSWORD}
DOCKER_INFLUXDB_INIT_ORG: omni-pca
DOCKER_INFLUXDB_INIT_BUCKET: ha
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUX_TOKEN}
DOCKER_INFLUXDB_INIT_RETENTION: 30d
volumes:
- influxdb-data:/var/lib/influxdb2
- influxdb-config:/etc/influxdb2
ports:
- "8086:8086"
networks:
- default
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8086/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
grafana:
image: grafana/grafana:11.4.0
container_name: omni-pca-dev-grafana
restart: unless-stopped
depends_on:
influxdb:
condition: service_healthy
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
GF_AUTH_ANONYMOUS_ENABLED: "false"
GF_USERS_ALLOW_SIGN_UP: "false"
GF_LOG_LEVEL: warn
INFLUX_URL: http://influxdb:8086
INFLUX_TOKEN: ${INFLUX_TOKEN}
volumes:
- grafana-data:/var/lib/grafana
- ../grafana/provisioning:/etc/grafana/provisioning:ro
ports:
- "3000:3000"
networks:
- default
- caddy
labels:
caddy: grafana-omni.juliet.warehack.ing
caddy.reverse_proxy: "{{upstreams 3000}}"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health || exit 1"]
interval: 10s
timeout: 3s
retries: 5
start_period: 15s
volumes:
influxdb-data:
influxdb-config:
grafana-data:
networks:
caddy:
external: true

19
grafana/.env.example Normal file
View File

@ -0,0 +1,19 @@
# Copy to .env and fill in. Both files in this directory load .env
# automatically via docker compose; ./env.example is committed, .env
# is gitignored.
# InfluxDB v2 admin user (created on first boot).
INFLUX_USERNAME=admin
INFLUX_PASSWORD=change-me-strong-password-here
# Admin token used by Home Assistant (writes) and Grafana (reads).
# Generate one with: openssl rand -hex 32
INFLUX_TOKEN=replace-with-a-real-token-from-openssl-rand-hex-32
# Grafana admin password (UI login as "admin"/this value).
GRAFANA_PASSWORD=change-me-too
# Public hostnames if you're putting either service behind a reverse
# proxy. Leave blank for localhost-only access.
INFLUX_PUBLIC_HOST=
GRAFANA_PUBLIC_HOST=

129
grafana/README.md Normal file
View File

@ -0,0 +1,129 @@
# Grafana dashboard for omni_pca
InfluxDB v2 + Grafana stack pre-provisioned to visualise an HAI/Leviton
Omni Pro II panel via the `omni_pca` Home Assistant integration.
Drop-in for any existing HA install — no integration changes required.
![Dashboard overview](../dev/artifacts/screenshots/2026-05-17/grafana-dashboard-final.png)
## What you get
One dashboard, four rows:
- **System health** — AC power, backup battery, system trouble, event count (24h).
- **Security** — area arming state timeline, recent push-event log, zone trip timeline.
- **Climate** — per-thermostat current temperatures + setpoints, HVAC mode timeline.
- **Activity** — event rate by typed event class, unit brightness heatmap.
Data flows: HA entity state → HA's `influxdb:` integration → InfluxDB
v2 bucket → Grafana Flux queries → dashboard panels.
## Quick start (~5 minutes)
```bash
cd grafana/
cp .env.example .env
# Edit .env — set strong INFLUX_PASSWORD, INFLUX_TOKEN, GRAFANA_PASSWORD.
# Generate the token with: openssl rand -hex 32
docker compose up -d
```
Wait ~30 seconds. InfluxDB does first-boot setup (creates the
`omni-pca` org, `ha` bucket, admin token); Grafana then auto-provisions
the InfluxDB datasource and the dashboard.
Then add the influxdb integration to your Home Assistant config:
```bash
# Paste the contents of ha-snippet.yaml into your configuration.yaml.
# Add `influxdb_token: <your INFLUX_TOKEN from .env>` to your secrets.yaml.
# Restart HA.
```
Within ~30 seconds you should see real-time data populating the
dashboard at <http://localhost:3000> (login: `admin` / your
`GRAFANA_PASSWORD`).
## Networking notes
The default `ha-snippet.yaml` assumes HA and InfluxDB sit on the same
docker network and HA can reach `influxdb:8086` by container name.
Three common variants:
| HA layout | `host:` value |
|---|---|
| Same compose stack as this bundle | `influxdb` |
| HA on the host, InfluxDB in docker | `host.docker.internal` or your LAN IP |
| Different machine entirely | the InfluxDB host's IP / FQDN |
If you put either service behind a reverse proxy with TLS, set `ssl:
true` in the HA snippet and supply the public hostname.
## Iterating on the dashboard
The dashboard JSON at `provisioning/dashboards/omni-pro-ii.json` is
loaded read-only by the provisioner. To change it:
1. Edit the JSON directly, then `docker compose restart grafana`
(provisioner picks up changes within ~30s).
2. Or use the Grafana UI to experiment, then **Dashboard settings →
JSON Model → Save to file** and overwrite the file in this repo.
Provisioned dashboards can't be saved from the UI by design — this is
intentional, so the file on disk stays the source of truth.
## Extending coverage
The bundle is scoped to the `omni_pca` entity surface via the
`entity_globs: ["*omni*"]` filter in `ha-snippet.yaml`. Drop that
filter (or add a second `include:` block) if you want to graph other
HA entities alongside omni data — Grafana's datasource is general
InfluxDB v2, nothing in the dashboard JSON hard-codes omni-specific
field names beyond what you'd want to scope to anyway.
A few panel ideas not yet shipped:
- Alarm activation drill-down — filter the event log to
`event_type == "alarm_activated"` and show the `alarm_type`
(Burglary / Fire / Auxiliary / …) distribution.
- Zone trip rate histogram — `binary_sensor` zone changes per zone
per hour, useful for spotting flaky sensors.
- Comm health — track integration coordinator state via the panel
device's "Comm error" attribute.
## Files in this bundle
| File | Purpose |
|---|---|
| `docker-compose.yml` | InfluxDB v2 + Grafana services |
| `.env.example` | Required environment template |
| `ha-snippet.yaml` | HA configuration.yaml additions |
| `provisioning/datasources/influxdb.yml` | Auto-wires the datasource |
| `provisioning/dashboards/dashboards.yml` | Provisioner config |
| `provisioning/dashboards/omni-pro-ii.json` | The dashboard JSON |
## Troubleshooting
**"No data" in panels.** Most panels need either continuous state
updates (climate, security) or push events (event-driven panels).
Verify HA is shipping data:
```bash
docker exec -it omni-pca-influxdb influx query \
'from(bucket:"ha") |> range(start:-5m) |> limit(n:5)' \
--token "$INFLUX_TOKEN" --org omni-pca
```
If this returns rows, the pipeline is healthy and panels will fill in
as the panel does interesting things. If it's empty, check HA logs for
`[homeassistant.components.influxdb]` errors.
**Dashboard didn't auto-load.** Check `docker logs omni-pca-grafana
2>&1 | grep -i provision` — provisioner errors show up there.
**Stat panels show duplicate values.** Your HA has multiple entities
matching the regex (e.g. `omni_pro_ii_ac_power` AND
`omni_pro_ii_ac_power_2` from prior integration reloads). Clean up the
duplicates in HA's entity registry, or tighten the filter in the
dashboard JSON.

View File

@ -0,0 +1,69 @@
# Self-contained InfluxDB v2 + Grafana stack for the omni_pca
# integration. Pre-provisioned with the InfluxDB datasource and the
# "Omni Pro II — Panel Overview" dashboard.
#
# Usage:
# cp .env.example .env && edit the secrets && docker compose up -d
# open http://localhost:3000 (admin / $GRAFANA_PASSWORD)
#
# Then paste the contents of ha-snippet.yaml into your HA
# configuration.yaml (and add `influxdb_token: $INFLUX_TOKEN` to
# secrets.yaml). Restart HA. Within 30s the dashboard's panels start
# filling in.
services:
influxdb:
image: influxdb:2.7-alpine
container_name: omni-pca-influxdb
restart: unless-stopped
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUX_USERNAME:-admin}
DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUX_PASSWORD}
DOCKER_INFLUXDB_INIT_ORG: omni-pca
DOCKER_INFLUXDB_INIT_BUCKET: ha
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUX_TOKEN}
DOCKER_INFLUXDB_INIT_RETENTION: 30d
volumes:
- influxdb-data:/var/lib/influxdb2
- influxdb-config:/etc/influxdb2
ports:
- "8086:8086"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8086/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
grafana:
image: grafana/grafana:11.4.0
container_name: omni-pca-grafana
restart: unless-stopped
depends_on:
influxdb:
condition: service_healthy
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
GF_AUTH_ANONYMOUS_ENABLED: "false"
GF_USERS_ALLOW_SIGN_UP: "false"
GF_LOG_LEVEL: warn
# Consumed by ./provisioning/datasources/influxdb.yml
INFLUX_URL: http://influxdb:8086
INFLUX_TOKEN: ${INFLUX_TOKEN}
volumes:
- grafana-data:/var/lib/grafana
- ./provisioning:/etc/grafana/provisioning:ro
ports:
- "3000:3000"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health || exit 1"]
interval: 10s
timeout: 3s
retries: 5
start_period: 15s
volumes:
influxdb-data:
influxdb-config:
grafana-data:

51
grafana/ha-snippet.yaml Normal file
View File

@ -0,0 +1,51 @@
# Paste this block into your Home Assistant configuration.yaml.
#
# Prerequisites:
# 1. The grafana stack from this directory is running:
# cd grafana/ && cp .env.example .env && docker compose up -d
# 2. Your HA instance can reach the influxdb container on port 8086.
# Common patterns:
# - HA and InfluxDB on the same compose stack: use host=influxdb
# - HA and InfluxDB on different hosts: use host=<your-influx-ip>
# - HA on the host network, InfluxDB in docker: use
# host=host.docker.internal or the host's LAN IP
# 3. Add `influxdb_token: <your INFLUX_TOKEN from .env>` to your
# secrets.yaml. Restart HA after editing both files.
#
# What this ships:
# - All state changes from omni_pca entities (alarm_control_panel,
# binary_sensor, climate, event, light, sensor, switch).
# - Event entity attributes carried as fields, including the typed
# event_class and event_data payload — so Flux queries can filter
# by alarm_type, zone_index, etc.
#
# Adjust the entity_globs filter if you also want non-omni entities in
# the dashboard, or tighten it further to scope by area / device.
influxdb:
api_version: 2
host: influxdb # change to match your network layout
port: 8086
ssl: false
verify_ssl: false
token: !secret influxdb_token
organization: omni-pca
bucket: ha
precision: s
# Tag the typed event kind so Flux queries can filter by it cheaply.
tags_attributes:
- event_type
- event_class
include:
domains:
- alarm_control_panel
- binary_sensor
- climate
- event
- light
- sensor
- switch
entity_globs:
- "*omni*" # scope to omni_pca entities only

View File

@ -0,0 +1,19 @@
# Tells Grafana to scan /etc/grafana/provisioning/dashboards for
# *.json dashboard files at boot. Picks up omni-pro-ii.json
# automatically. Dashboards loaded this way are read-only in the UI;
# the source of truth is the JSON in this directory.
apiVersion: 1
providers:
- name: omni-pca
orgId: 1
folder: ''
folderUid: ''
type: file
disableDeletion: false
updateIntervalSeconds: 30
allowUiUpdates: false
options:
path: /etc/grafana/provisioning/dashboards
foldersFromFilesStructure: false

View File

@ -0,0 +1,682 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {"type": "grafana", "uid": "-- Grafana --"},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"description": "Live view of an HAI/Leviton Omni Pro II panel surfaced by the omni_pca Home Assistant integration. System health, security activity, climate trends, and the typed push-event stream — all sourced from InfluxDB writes shipped by HA's influxdb integration.",
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"collapsed": false,
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 0},
"id": 100,
"panels": [],
"title": "System health",
"type": "row"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"mappings": [
{"options": {"0": {"color": "red", "index": 0, "text": "LOST"}}, "type": "value"},
{"options": {"1": {"color": "green", "index": 1, "text": "OK"}}, "type": "value"}
],
"thresholds": {"mode": "absolute", "steps": [{"color": "red"}, {"color": "green", "value": 1}]},
"unit": "none"
}
},
"gridPos": {"h": 5, "w": 6, "x": 0, "y": 1},
"id": 101,
"options": {
"colorMode": "background",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false},
"textMode": "auto"
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: -24h)\n |> filter(fn: (r) => r.domain == \"binary_sensor\")\n |> filter(fn: (r) => r.entity_id =~ /ac_power/ and not (r.entity_id =~ /_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"value\")\n |> last()\n |> group()",
"refId": "A"
}
],
"title": "AC power",
"type": "stat"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"mappings": [
{"options": {"0": {"color": "green", "index": 0, "text": "OK"}}, "type": "value"},
{"options": {"1": {"color": "red", "index": 1, "text": "LOW"}}, "type": "value"}
],
"thresholds": {"mode": "absolute", "steps": [{"color": "green"}, {"color": "red", "value": 1}]}
}
},
"gridPos": {"h": 5, "w": 6, "x": 6, "y": 1},
"id": 102,
"options": {
"colorMode": "background",
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false},
"textMode": "auto"
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: -24h)\n |> filter(fn: (r) => r.domain == \"binary_sensor\")\n |> filter(fn: (r) => r.entity_id =~ /battery/ and not (r.entity_id =~ /_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"value\")\n |> last()\n |> group()",
"refId": "A"
}
],
"title": "Backup battery",
"type": "stat"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"mappings": [
{"options": {"0": {"color": "green", "index": 0, "text": "Clear"}}, "type": "value"},
{"options": {"1": {"color": "red", "index": 1, "text": "Trouble"}}, "type": "value"}
],
"thresholds": {"mode": "absolute", "steps": [{"color": "green"}, {"color": "red", "value": 1}]}
}
},
"gridPos": {"h": 5, "w": 6, "x": 12, "y": 1},
"id": 103,
"options": {
"colorMode": "background",
"graphMode": "none",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false},
"textMode": "auto"
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: -24h)\n |> filter(fn: (r) => r.domain == \"binary_sensor\")\n |> filter(fn: (r) => r.entity_id =~ /trouble/ and not (r.entity_id =~ /_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"value\")\n |> last()\n |> group()",
"refId": "A"
}
],
"title": "System trouble",
"type": "stat"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Count of panel push events in the last 24 hours. Empty until the panel pushes its first event (the mock fires events when HA actions trigger panel state changes; a real panel pushes continuously).",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"thresholds": {"mode": "absolute", "steps": [{"color": "blue"}, {"color": "green", "value": 1}]},
"unit": "short"
}
},
"gridPos": {"h": 5, "w": 6, "x": 18, "y": 1},
"id": 104,
"options": {
"colorMode": "background",
"graphMode": "area",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false},
"textMode": "auto"
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: -24h)\n |> filter(fn: (r) => r.domain == \"event\")\n |> filter(fn: (r) => r._field == \"state\")\n |> group()\n |> count()",
"refId": "A"
}
],
"title": "Events (24h)",
"type": "stat"
},
{
"collapsed": false,
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 6},
"id": 200,
"panels": [],
"title": "Security",
"type": "row"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Arming state per area. Disarmed = green, day = teal, night = blue, away = orange, vacation = magenta, triggered = red, arming/pending = yellow.",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"custom": {"fillOpacity": 80, "lineWidth": 0},
"mappings": [
{"options": {"disarmed": {"color": "#43aa8b", "text": "disarmed"}}, "type": "value"},
{"options": {"armed_home": {"color": "#577590", "text": "armed home"}}, "type": "value"},
{"options": {"armed_night": {"color": "#277da1", "text": "armed night"}}, "type": "value"},
{"options": {"armed_away": {"color": "#f8961e", "text": "armed away"}}, "type": "value"},
{"options": {"armed_vacation": {"color": "#a663cc", "text": "armed vacation"}}, "type": "value"},
{"options": {"armed_custom_bypass": {"color": "#90be6d", "text": "armed custom"}}, "type": "value"},
{"options": {"arming": {"color": "#f9c74f", "text": "arming"}}, "type": "value"},
{"options": {"pending": {"color": "#f9c74f", "text": "pending"}}, "type": "value"},
{"options": {"triggered": {"color": "#d62828", "text": "TRIGGERED"}}, "type": "value"}
],
"thresholds": {"mode": "absolute", "steps": [{"color": "#6c757d"}]}
}
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 7},
"id": 201,
"options": {
"legend": {"displayMode": "list", "placement": "bottom", "showLegend": true},
"mergeValues": true,
"rowHeight": 0.9,
"showValue": "auto",
"tooltip": {"mode": "single"}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"alarm_control_panel\")\n |> filter(fn: (r) => r._field == \"state\")\n |> filter(fn: (r) => not (r.entity_id =~ /_[0-9]+$/))\n |> keep(columns: [\"_time\", \"_value\", \"entity_id\"])\n |> group(columns: [\"entity_id\"])",
"refId": "A"
}
],
"title": "Area arming state",
"type": "state-timeline"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Push events the panel sent in the selected window. Columns: time, typed event_type, object index (zone / unit / area / user), and new_state for state-changed events.",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"custom": {
"align": "auto",
"cellOptions": {"type": "auto"},
"inspect": false
},
"thresholds": {"mode": "absolute", "steps": [{"color": "transparent"}]}
},
"overrides": [
{
"matcher": {"id": "byName", "options": "event_type"},
"properties": [
{"id": "custom.cellOptions", "value": {"type": "color-background", "mode": "basic"}},
{"id": "mappings", "value": [
{"options": {"alarm_activated": {"color": "#d62828", "text": "alarm_activated"}}, "type": "value"},
{"options": {"alarm_cleared": {"color": "#43aa8b", "text": "alarm_cleared"}}, "type": "value"},
{"options": {"ac_lost": {"color": "#d62828", "text": "ac_lost"}}, "type": "value"},
{"options": {"ac_restored": {"color": "#43aa8b", "text": "ac_restored"}}, "type": "value"},
{"options": {"battery_low": {"color": "#f8961e", "text": "battery_low"}}, "type": "value"},
{"options": {"battery_restored": {"color": "#43aa8b", "text": "battery_restored"}}, "type": "value"},
{"options": {"zone_state_changed": {"color": "#577590", "text": "zone_state_changed"}}, "type": "value"},
{"options": {"unit_state_changed": {"color": "#90be6d", "text": "unit_state_changed"}}, "type": "value"},
{"options": {"arming_changed": {"color": "#f9c74f", "text": "arming_changed"}}, "type": "value"},
{"options": {"user_macro_button": {"color": "#277da1", "text": "user_macro_button"}}, "type": "value"},
{"options": {"phone_line_dead": {"color": "#f8961e", "text": "phone_line_dead"}}, "type": "value"},
{"options": {"phone_line_restored": {"color": "#43aa8b", "text": "phone_line_restored"}}, "type": "value"}
]}
]
},
{
"matcher": {"id": "byName", "options": "_time"},
"properties": [
{"id": "custom.width", "value": 175},
{"id": "displayName", "value": "time"}
]
}
]
},
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 7},
"id": 202,
"options": {
"cellHeight": "sm",
"footer": {"countRows": false, "fields": "", "reducer": ["sum"], "show": false},
"showHeader": true,
"sortBy": [{"desc": true, "displayName": "time"}]
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"event\")\n |> filter(fn: (r) => r._field == \"new_state\" or r._field == \"unit_index\" or r._field == \"zone_index\" or r._field == \"area_index\" or r._field == \"user_index\" or r._field == \"alarm_type\" or r._field == \"button_index\")\n |> pivot(rowKey: [\"_time\", \"event_type\"], columnKey: [\"_field\"], valueColumn: \"_value\")\n |> drop(columns: [\"_start\", \"_stop\", \"_measurement\", \"domain\", \"entity_id\", \"event_class\"])\n |> group()\n |> sort(columns: [\"_time\"], desc: true)\n |> limit(n: 50)",
"refId": "A"
}
],
"title": "Recent panel events",
"type": "table"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Zone open/closed timeline. Painted segments = zone is_on (open / tripped).",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"custom": {"fillOpacity": 70, "lineWidth": 0},
"mappings": [
{"options": {"0": {"color": "green", "index": 0, "text": "secure"}}, "type": "value"},
{"options": {"1": {"color": "orange", "index": 1, "text": "open"}}, "type": "value"}
],
"thresholds": {"mode": "absolute", "steps": [{"color": "green"}, {"color": "orange", "value": 1}]}
}
},
"gridPos": {"h": 8, "w": 24, "x": 0, "y": 15},
"id": 203,
"options": {
"legend": {"displayMode": "list", "placement": "bottom", "showLegend": false},
"mergeValues": true,
"rowHeight": 0.9,
"showValue": "never",
"tooltip": {"mode": "single"}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"binary_sensor\")\n |> filter(fn: (r) => not (r.entity_id =~ /ac_power|battery|trouble|bypass|_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"value\")\n |> keep(columns: [\"_time\", \"_value\", \"entity_id\"])\n |> group(columns: [\"entity_id\"])",
"refId": "A"
}
],
"title": "Zone trip timeline",
"type": "state-timeline"
},
{
"collapsed": false,
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 23},
"id": 300,
"panels": [],
"title": "Climate",
"type": "row"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Current temperature per thermostat. Mock fixture values are raw panel format; a real panel reports °F.",
"fieldConfig": {
"defaults": {
"color": {"mode": "fixed", "fixedColor": "#f1faee"},
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 8,
"gradientMode": "opacity",
"lineInterpolation": "stepBefore",
"lineWidth": 2,
"pointSize": 4,
"showPoints": "auto",
"spanNulls": true
},
"unit": "celsius"
},
"overrides": [
{
"matcher": {"id": "byFrameRefID", "options": "A"},
"properties": [{"id": "color", "value": {"mode": "palette-classic-by-name"}}]
}
]
},
"gridPos": {"h": 9, "w": 16, "x": 0, "y": 24},
"id": 301,
"options": {
"legend": {"calcs": ["mean", "lastNotNull"], "displayMode": "table", "placement": "right", "showLegend": true},
"tooltip": {"mode": "multi", "sort": "desc"}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"climate\")\n |> filter(fn: (r) => not (r.entity_id =~ /_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"current_temperature\")\n |> keep(columns: [\"_time\", \"_value\", \"entity_id\"])\n |> group(columns: [\"entity_id\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)",
"refId": "A"
}
],
"title": "Thermostat temperatures",
"type": "timeseries"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "HVAC system mode per thermostat over the selected window. Off = grey, Heat = orange, Cool = blue, Auto = green, Dry = teal, Fan only = yellow.",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"custom": {"fillOpacity": 80, "lineWidth": 0},
"mappings": [
{"options": {"off": {"color": "#adb5bd", "text": "off"}}, "type": "value"},
{"options": {"heat": {"color": "#f3722c", "text": "heat"}}, "type": "value"},
{"options": {"cool": {"color": "#277da1", "text": "cool"}}, "type": "value"},
{"options": {"heat_cool":{"color": "#43aa8b", "text": "auto"}}, "type": "value"},
{"options": {"auto": {"color": "#43aa8b", "text": "auto"}}, "type": "value"},
{"options": {"dry": {"color": "#577590", "text": "dry"}}, "type": "value"},
{"options": {"fan_only": {"color": "#f9c74f", "text": "fan only"}}, "type": "value"}
],
"thresholds": {"mode": "absolute", "steps": [{"color": "#adb5bd"}]}
}
},
"gridPos": {"h": 9, "w": 8, "x": 16, "y": 24},
"id": 302,
"options": {
"legend": {"displayMode": "list", "placement": "bottom", "showLegend": true},
"mergeValues": true,
"rowHeight": 0.9,
"showValue": "auto",
"tooltip": {"mode": "single"}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"climate\")\n |> filter(fn: (r) => r._field == \"state\")\n |> filter(fn: (r) => not (r.entity_id =~ /_[0-9]+$/))\n |> keep(columns: [\"_time\", \"_value\", \"entity_id\"])\n |> group(columns: [\"entity_id\"])",
"refId": "A"
}
],
"title": "HVAC mode",
"type": "state-timeline"
},
{
"collapsed": false,
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 33},
"id": 400,
"panels": [],
"title": "Activity",
"type": "row"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Panel event rate, bucketed by event_type. Tracks zone state changes, button presses, alarm activation, AC/battery events, etc. Each event_type has its own color matching the events table.",
"fieldConfig": {
"defaults": {
"color": {"mode": "palette-classic"},
"custom": {
"drawStyle": "bars",
"fillOpacity": 80,
"lineWidth": 0,
"showPoints": "never",
"stacking": {"mode": "normal"}
},
"unit": "short"
},
"overrides": [
{"matcher": {"id": "byName", "options": "alarm_activated"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#d62828"}}]},
{"matcher": {"id": "byName", "options": "alarm_cleared"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]},
{"matcher": {"id": "byName", "options": "ac_lost"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#d62828"}}]},
{"matcher": {"id": "byName", "options": "ac_restored"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]},
{"matcher": {"id": "byName", "options": "battery_low"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#f8961e"}}]},
{"matcher": {"id": "byName", "options": "battery_restored"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]},
{"matcher": {"id": "byName", "options": "zone_state_changed"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#577590"}}]},
{"matcher": {"id": "byName", "options": "unit_state_changed"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#90be6d"}}]},
{"matcher": {"id": "byName", "options": "arming_changed"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#f9c74f"}}]},
{"matcher": {"id": "byName", "options": "user_macro_button"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#277da1"}}]},
{"matcher": {"id": "byName", "options": "phone_line_dead"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#f8961e"}}]},
{"matcher": {"id": "byName", "options": "phone_line_restored"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]}
]
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 34},
"id": 401,
"options": {
"legend": {"displayMode": "table", "placement": "right", "showLegend": true, "calcs": ["sum"]},
"tooltip": {"mode": "multi", "sort": "desc"}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"event\")\n |> filter(fn: (r) => r._field == \"state\")\n |> group(columns: [\"event_type\"])\n |> aggregateWindow(every: v.windowPeriod, fn: count, createEmpty: true)",
"refId": "A"
}
],
"title": "Event rate by type",
"type": "timeseries"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Top 15 most-toggled units in the selected window — bar length = number of state changes. Reveals which lights/relays get used most.",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "#f9c74f", "value": null},
{"color": "#f8961e", "value": 5},
{"color": "#f3722c", "value": 15},
{"color": "#d62828", "value": 30}
]
},
"min": 0,
"unit": "short"
}
},
"gridPos": {"h": 10, "w": 12, "x": 12, "y": 34},
"id": 402,
"options": {
"displayMode": "gradient",
"valueMode": "color",
"showUnfilled": true,
"orientation": "horizontal",
"reduceOptions": {"calcs": ["lastNotNull"], "fields": "/^_value$/", "values": true},
"minVizHeight": 10,
"minVizWidth": 0,
"namePlacement": "left"
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"light\")\n |> filter(fn: (r) => not (r.entity_id =~ /_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"value\")\n |> toFloat()\n |> keep(columns: [\"_value\", \"entity_id\"])\n |> group(columns: [\"entity_id\"])\n |> count()\n |> group()\n |> sort(columns: [\"_value\"], desc: true)\n |> limit(n: 15)",
"refId": "A"
}
],
"title": "Top toggled units (24h)",
"type": "bargauge"
},
{
"collapsed": false,
"gridPos": {"h": 1, "w": 24, "x": 0, "y": 44},
"id": 500,
"panels": [],
"title": "Insights",
"type": "row"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Zones currently bypassed. Bypass = the panel ignores this zone for arming/alarm purposes. Empty when nothing is bypassed; rows accrue when a switch is flipped.",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"custom": {
"align": "auto",
"cellOptions": {"type": "auto"},
"inspect": false
},
"thresholds": {"mode": "absolute", "steps": [{"color": "transparent"}]}
},
"overrides": [
{
"matcher": {"id": "byName", "options": "entity_id"},
"properties": [
{"id": "displayName", "value": "zone bypass switch"},
{"id": "custom.cellOptions", "value": {"type": "color-text", "wrapText": false}},
{"id": "color", "value": {"mode": "fixed", "fixedColor": "#f9c74f"}}
]
},
{
"matcher": {"id": "byName", "options": "_time"},
"properties": [
{"id": "displayName", "value": "since"},
{"id": "custom.width", "value": 175}
]
},
{
"matcher": {"id": "byName", "options": "_value"},
"properties": [{"id": "custom.hidden", "value": true}]
}
]
},
"gridPos": {"h": 8, "w": 8, "x": 0, "y": 45},
"id": 501,
"options": {
"cellHeight": "sm",
"footer": {"countRows": true, "fields": "", "reducer": ["sum"], "show": true},
"showHeader": true,
"sortBy": [{"desc": true, "displayName": "since"}]
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: -24h)\n |> filter(fn: (r) => r.domain == \"switch\")\n |> filter(fn: (r) => not (r.entity_id =~ /_[0-9]+$/))\n |> filter(fn: (r) => r._field == \"value\")\n |> last()\n |> filter(fn: (r) => r._value > 0.0)\n |> keep(columns: [\"_time\", \"_value\", \"entity_id\"])\n |> group()\n |> sort(columns: [\"_time\"], desc: true)",
"refId": "A"
}
],
"title": "Active zone bypasses",
"type": "table"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "User-macro button press events from the panel. Each row = one press; button_index identifies which scene/macro fired.",
"fieldConfig": {
"defaults": {
"color": {"mode": "thresholds"},
"custom": {
"align": "auto",
"cellOptions": {"type": "auto"},
"inspect": false
},
"thresholds": {"mode": "absolute", "steps": [{"color": "transparent"}]}
},
"overrides": [
{
"matcher": {"id": "byName", "options": "button_index"},
"properties": [
{"id": "displayName", "value": "button #"},
{"id": "custom.cellOptions", "value": {"type": "color-background", "mode": "basic"}},
{"id": "color", "value": {"mode": "fixed", "fixedColor": "#277da1"}}
]
},
{
"matcher": {"id": "byName", "options": "_time"},
"properties": [
{"id": "displayName", "value": "time"},
{"id": "custom.width", "value": 175}
]
}
]
},
"gridPos": {"h": 8, "w": 8, "x": 8, "y": 45},
"id": 502,
"options": {
"cellHeight": "sm",
"footer": {"countRows": true, "fields": "", "reducer": ["sum"], "show": true},
"showHeader": true,
"sortBy": [{"desc": true, "displayName": "time"}]
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"event\" and r.event_type == \"user_macro_button\")\n |> filter(fn: (r) => r._field == \"button_index\")\n |> keep(columns: [\"_time\", \"_value\"])\n |> group()\n |> sort(columns: [\"_time\"], desc: true)\n |> limit(n: 25)\n |> rename(columns: {_value: \"button_index\"})",
"refId": "A"
}
],
"title": "Button press log",
"type": "table"
},
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"description": "Distribution of panel push events by typed kind across the selected window. Matches the colors used in the event rate and events table panels.",
"fieldConfig": {
"defaults": {
"color": {"mode": "palette-classic"},
"custom": {
"hideFrom": {"legend": false, "tooltip": false, "viz": false}
},
"mappings": []
},
"overrides": [
{"matcher": {"id": "byName", "options": "alarm_activated"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#d62828"}}]},
{"matcher": {"id": "byName", "options": "alarm_cleared"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]},
{"matcher": {"id": "byName", "options": "ac_lost"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#d62828"}}]},
{"matcher": {"id": "byName", "options": "ac_restored"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]},
{"matcher": {"id": "byName", "options": "battery_low"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#f8961e"}}]},
{"matcher": {"id": "byName", "options": "battery_restored"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#43aa8b"}}]},
{"matcher": {"id": "byName", "options": "zone_state_changed"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#577590"}}]},
{"matcher": {"id": "byName", "options": "unit_state_changed"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#90be6d"}}]},
{"matcher": {"id": "byName", "options": "arming_changed"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#f9c74f"}}]},
{"matcher": {"id": "byName", "options": "user_macro_button"}, "properties": [{"id": "color", "value": {"mode": "fixed", "fixedColor": "#277da1"}}]}
]
},
"gridPos": {"h": 8, "w": 8, "x": 16, "y": 45},
"id": 503,
"options": {
"displayLabels": ["percent", "name"],
"legend": {"displayMode": "table", "placement": "right", "showLegend": true, "values": ["value"]},
"pieType": "donut",
"reduceOptions": {"calcs": ["sum"], "fields": "", "values": false},
"tooltip": {"mode": "single", "sort": "none"}
},
"pluginVersion": "11.4.0",
"targets": [
{
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"query": "from(bucket: \"ha\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r.domain == \"event\" and r._field == \"state\")\n |> keep(columns: [\"_time\", \"_value\", \"event_type\"])\n |> group(columns: [\"event_type\"])\n |> count(column: \"_value\")\n |> map(fn: (r) => ({_time: now(), _value: r._value, event_type: r.event_type}))\n |> pivot(rowKey: [\"_time\"], columnKey: [\"event_type\"], valueColumn: \"_value\")",
"refId": "A"
}
],
"title": "Event distribution",
"type": "piechart"
}
],
"refresh": "30s",
"schemaVersion": 39,
"tags": ["omni-pca", "hai", "omni-pro-ii", "home-assistant"],
"templating": {
"list": [
{
"current": {"selected": true, "text": "All", "value": "$__all"},
"datasource": {"type": "influxdb", "uid": "InfluxDB"},
"definition": "from(bucket: \"ha\") |> range(start: -7d) |> filter(fn: (r) => r.domain == \"event\" and r._field == \"state\") |> keep(columns: [\"event_type\"]) |> group() |> distinct(column: \"event_type\")",
"hide": 0,
"includeAll": true,
"label": "Event type",
"multi": true,
"name": "event_type",
"options": [],
"query": "from(bucket: \"ha\") |> range(start: -7d) |> filter(fn: (r) => r.domain == \"event\" and r._field == \"state\") |> keep(columns: [\"event_type\"]) |> group() |> distinct(column: \"event_type\")",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
}
]
},
"time": {"from": "now-24h", "to": "now"},
"timepicker": {
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h"],
"time_options": ["1h", "6h", "24h", "2d", "7d", "30d"]
},
"timezone": "browser",
"title": "Omni Pro II — Panel Overview",
"uid": "omni-pro-ii-overview",
"version": 1,
"weekStart": ""
}

View File

@ -0,0 +1,21 @@
# Auto-wires the InfluxDB v2 datasource at Grafana boot. Picks up
# INFLUX_URL and INFLUX_TOKEN from the grafana container's environment
# (set in docker-compose.yml from .env). No manual datasource config
# needed.
apiVersion: 1
datasources:
- name: InfluxDB
type: influxdb
access: proxy
url: ${INFLUX_URL}
isDefault: true
editable: false
jsonData:
version: Flux
organization: omni-pca
defaultBucket: ha
tlsSkipVerify: true
secureJsonData:
token: ${INFLUX_TOKEN}