diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2735761
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch
+.vscode/extensions.json
+.vscode/settings.json
+extra.ini
+data/mqtt_root_ca.pem
+data/mqtt_server_cert.pem
+data/root_ca.pem
+docker/nodered/.npm
+docker/nodered/node_modules
+docker/nodered/*.backup
+docker/influxdb/engine
+docker/nodered/package-lock.json
+docker/influxdb/data
+docker/influxdb/config
+docker/grafana/alerting
+docker/grafana/grafana.db
+docker/nodered/.config.runtime.json
+docker/nodered/.config.users.json
+docker/nodered/flows_cred.json
diff --git a/boards/esp32-s3-1-4.json b/boards/esp32-s3-1-4.json
new file mode 100644
index 0000000..14ed279
--- /dev/null
+++ b/boards/esp32-s3-1-4.json
@@ -0,0 +1,37 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "esp32s3_out.ld"
+ },
+ "core": "esp32",
+ "extra_flags": [
+ "-DARDUINO_ESP32S3_DEV",
+ "-DARDUINO_USB_MODE=1",
+ "-DARDUINO_RUNNING_CORE=1",
+ "-DARDUINO_EVENT_RUNNING_CORE=1"
+ ],
+ "f_cpu": "240000000L",
+ "f_flash": "80000000L",
+ "flash_mode": "qio",
+ "hwids": [["0X303A", "0x1001"]],
+ "mcu": "esp32s3",
+ "variant": "esp32s3"
+ },
+ "connectivity": ["wifi"],
+ "debug": {
+ "default_tool": "esp-builtin",
+ "onboard_tools": ["esp-builtin"],
+ "openocd_target": "esp32s3.cfg"
+ },
+ "frameworks": ["arduino", "espidf"],
+ "name": "Espressif ESP32-S3-1-N4 (4 MB QD, No PSRAM)",
+ "upload": {
+ "flash_size": "4MB",
+ "maximum_ram_size": 327680,
+ "maximum_size": 4194304,
+ "require_upload_port": true,
+ "speed": 460800
+ },
+ "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html",
+ "vendor": "Espressif"
+}
diff --git a/data/config.json b/data/config.json
new file mode 100644
index 0000000..9b7554e
--- /dev/null
+++ b/data/config.json
@@ -0,0 +1,12 @@
+{
+ "deviceId": 0,
+ "mqttTopic": "aranetproxy",
+ "mqttUsername": "aranetproxy",
+ "mqttPassword": "aranetproxy",
+ "mqttHost": "127.0.0.1",
+ "mqttServerPort": 1883,
+ "mqttUseTls": false,
+ "mqttInsecure": false,
+ "ssd1306Rows": 64,
+ "scanInterval": 300
+}
diff --git a/docker/.env b/docker/.env
new file mode 100644
index 0000000..958bd70
--- /dev/null
+++ b/docker/.env
@@ -0,0 +1 @@
+TZ=Pacific/Auckland
diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml
new file mode 100644
index 0000000..b8aaba4
--- /dev/null
+++ b/docker/docker-compose.yaml
@@ -0,0 +1,84 @@
+version: "3"
+services:
+ mqtt:
+ image: eclipse-mosquitto:openssl
+ container_name: mosquitto
+ volumes:
+ - ./mosquitto/:/mosquitto/:rw
+ ports:
+ - "1883:1883"
+ networks:
+ - co2mon
+ env_file:
+ - .env
+ - mosquitto.env
+ restart: unless-stopped
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "1m"
+ max-file: "5"
+ nodered:
+ image: nodered/node-red
+ container_name: nodered
+ volumes:
+ - ./nodered:/data
+ ports:
+ - "1880:1880"
+ networks:
+ - co2mon
+ env_file:
+ - .env
+ - nodered.env
+ restart: unless-stopped
+ depends_on:
+ - influxdb
+ - mqtt
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "1m"
+ max-file: "5"
+ influxdb:
+ image: influxdb
+ container_name: influxdb
+ volumes:
+ - ./influxdb/data:/var/lib/influxdb2
+ - ./influxdb/config:/etc/influxdb2
+ ports:
+ - "8086:8086"
+ networks:
+ - co2mon
+ env_file:
+ - .env
+ - influxdb.env
+ restart: unless-stopped
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "1m"
+ max-file: "5"
+ grafana:
+ image: grafana/grafana
+ container_name: grafana
+ volumes:
+ - ./grafana:/var/lib/grafana
+ - ./grafana/provisioning:/etc/grafana/provisioning
+ ports:
+ - "3000:3000"
+ networks:
+ - co2mon
+ env_file:
+ - .env
+ - grafana.env
+ depends_on:
+ - influxdb
+ restart: unless-stopped
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "1m"
+ max-file: "5"
+networks:
+ co2mon:
+ driver: bridge
diff --git a/docker/docker.md b/docker/docker.md
new file mode 100644
index 0000000..f633125
--- /dev/null
+++ b/docker/docker.md
@@ -0,0 +1,78 @@
+# Docker backend running Mosquitto InfluxDB Node-Red Grafana
+
+## Preparation
+
+Before running the docker compose file have a look at the various \*.env files and change the provided default passwords.
+Make sure not to expose this directly to the internet without additional and read the following resources on further securing the various components
+
+- [Grafana](https://grafana.com/docs/grafana/next/setup-grafana/configure-security/)
+- [Node-Red](https://nodered.org/docs/user-guide/runtime/securing-node-red)
+- [Mosquitto](https://mosquitto.org/documentation/)
+- [InfluxDB](https://hub.docker.com/_/influxdb)
+- Set a `credentialSecret` in [Node Red's settings.js](./nodered/settings.js#L44)
+
+## Starting
+
+Run `docker-compose up`
+
+## Mosquitto
+
+- Mosquitto is pre-configured using the [mosquitto.acl](./mosquitto/config/mosquitto.acl) and [mosquitto.passwd](./mosquitto/config/mosquitto.passwd) files. The default users/passwords are
+ - `admin` // `admin`
+ - `aranetproxy` // `aranetproxy`
+ - `nodered` // `nodered`
+- to change any of the above passwords use `docker exec mosquitto mosquitto_passwd -b /mosquitto/config/mosquitto.passwd {username} {password}`. Restart Mosquitto for the changes to become effective `docker restart mosquitto`
+
+## Configure InfluxDB
+
+### Using the UI
+
+- Open http://127.0.0.1:8086/ and log on using the admin user and password form the [influxdb.env](influxdb.env) file
+- Navigate to `Load data` -> `API tokens` and generate a `Read/Write API Token` for Node-red
+ - Description `nodered`
+ - Select scoped read and write access for the `co2monitors` bucket
+ - the token will later be entered in a Node-red configuration node
+- Create another token for Grafana
+ - Description `grafana`
+ - Select scoped read access for the `co2monitors` bucket
+ - the token will later be entered in Grafana
+
+### Using the CLI
+
+- Create and note API tokens
+ - Node-red `docker exec influxdb bash -c "influx auth create -o CO2Monitors -d nodered --write-bucket $(influx bucket list | grep co2monitors | cut -f 1) --read-bucket $(influx bucket list | grep co2monitors | cut -f 1) | grep nodered | cut -f 4"`
+ - Grafana `docker exec influxdb bash -c "influx auth create -o CO2Monitors -d grafana --read-bucket $(influx bucket list | grep co2monitors | cut -f 1) | grep grafana | cut -f 4"`
+- (optional) run `docker exec influxdb bash -c "influx auth list --user admin --hide-headers | cut -f 3"` to retrieve the admin API token
+
+## Configure Node-Red
+
+### Using the UI
+
+- Open http://127.0.0.1:1880/
+- Open the `Manage palette` menu to add the missing plug-ins
+- Got to the `Install` tab and add the following plug-ins
+ - node-red-contrib-influxdb
+ - node-red-node-email
+- Open `Configuration nodes` in the menu and select open the `[v2.0] influxdb` node
+- Enter the `nodered` API token previously created in InfluxDB
+- Open the `Mosquitto` Docker configuration node and enter the Mosquitto username and password (default `nodered` // `nodered` )
+- Deploy the changes using the top right Deploy menu. Deploying `Modified nodes` only is sufficient. The Mosquitto nodes should now show `connected`
+- to enable email alerts and status messages configure the email node and enable it.
+
+### Using the CLI
+
+- Install the missing plug-ins `docker exec nodered npm install node-red-contrib-influxdb node-red-node-email`
+- Restart Node-Red `docker restart nodered`
+- Follow the steps above to configure the `Configuration nodes` on hte UI
+
+### Finishing
+
+- Once you have a CO2 monitor connected check out the Node-Red Dashboard http://127.0.0.1:1880/ui/. You might need to trigger the `Refresh monitors` flow in the `CO2 Monitors UI` tab first, or wait until it runs every hour.
+- The `Get configuration` flow on the `CO2 monitors` tab runs daily and queries all monitors for their current configuration. This will show on the UI once a monitor is selected in the drop down and is also visible in the dedicated Grafana dashboard.
+
+## Configure Grafana
+
+- Open http://127.0.0.1:3000/ and log in using the user and password configured in [`grafana.env`](grafana.env)
+- Open the `Data sources` entry from the bottom left Configuration menu and click on `InfluxDB`
+- Enter the grafana token previously created in Influx
+- Confirm with `Save and test`
diff --git a/docker/grafana.env b/docker/grafana.env
new file mode 100644
index 0000000..370bc4f
--- /dev/null
+++ b/docker/grafana.env
@@ -0,0 +1,8 @@
+GF_AUTH_ANONYMOUS_ENABLED=true
+GF_AUTH_ANONYMOUS_ORG_NAME=CO2Monitor
+GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
+GF_SECURITY_ADMIN_USER=admin
+GF_SECURITY_ADMIN_PASSWORD=*grafana-admin-password*
+GF_ANALYTICS_REPORTING_ENABLED=false
+GF_LIVE_ALLOWED_ORIGINS=*
+GF_PATHS_CONFIG=/var/lib/grafana/grafana.ini
\ No newline at end of file
diff --git a/docker/grafana/dashboards/CO2 Monitor detail.json b/docker/grafana/dashboards/CO2 Monitor detail.json
new file mode 100644
index 0000000..6ab3bd4
--- /dev/null
+++ b/docker/grafana/dashboards/CO2 Monitor detail.json
@@ -0,0 +1,1250 @@
+{
+ "__inputs": [
+ {
+ "name": "DS_INFLUXDB",
+ "label": "InfluxDB",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "influxdb",
+ "pluginName": "InfluxDB"
+ }
+ ],
+ "__elements": {},
+ "__requires": [
+ {
+ "type": "panel",
+ "id": "gauge",
+ "name": "Gauge",
+ "version": ""
+ },
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "9.4.3"
+ },
+ {
+ "type": "datasource",
+ "id": "influxdb",
+ "name": "InfluxDB",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "stat",
+ "name": "Stat",
+ "version": ""
+ },
+ {
+ "type": "panel",
+ "id": "text",
+ "name": "Text",
+ "version": ""
+ },
+ {
+ "type": "panel",
+ "id": "timeseries",
+ "name": "Time series",
+ "version": ""
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "datasource",
+ "uid": "grafana"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "gridPos": {
+ "h": 18,
+ "w": 3,
+ "x": 0,
+ "y": 0
+ },
+ "id": 18,
+ "options": {
+ "code": {
+ "language": "plaintext",
+ "showLineNumbers": false,
+ "showMiniMap": false
+ },
+ "content": "| room | sensor |\n| --------- | ------ |\n|Room x | x|\n",
+ "mode": "markdown"
+ },
+ "pluginVersion": "9.4.3",
+ "title": "Room to sensor id",
+ "type": "text"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "max": 2000,
+ "min": 0,
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ },
+ {
+ "color": "semi-dark-purple",
+ "value": 1200
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 5,
+ "x": 3,
+ "y": 0
+ },
+ "id": 14,
+ "options": {
+ "orientation": "vertical",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showThresholdLabels": false,
+ "showThresholdMarkers": true
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> last()\r\n |> drop(columns: [\"_field\"])\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [
+ 5
+ ],
+ "type": "moving_average"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "CO2",
+ "type": "gauge"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 5,
+ "x": 8,
+ "y": 0
+ },
+ "id": 16,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "auto"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> median()\r\n |> drop(columns: [\"_start\", \"_stop\", \"_field\"])\r\n |> map(fn: (r) => ({ r with _time: v.timeRangeStop}))\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [],
+ "type": "mean"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Median CO2",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 1,
+ "mappings": [],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "celsius"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 5,
+ "x": 13,
+ "y": 0
+ },
+ "id": 10,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "area",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"temperature\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> drop(columns: [\"_field\"])\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "temperature"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Temperature",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "max": 2000,
+ "min": 400,
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 5,
+ "x": 3,
+ "y": 9
+ },
+ "id": 7,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "area",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "auto"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> drop(columns: [\"_field\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [
+ 5
+ ],
+ "type": "moving_average"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "CO2",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 5,
+ "x": 8,
+ "y": 9
+ },
+ "id": 15,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "auto"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> max()\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [],
+ "type": "max"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Max CO2",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 1,
+ "mappings": [],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "humidity"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 5,
+ "x": 13,
+ "y": 9
+ },
+ "id": 11,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "area",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "auto"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"humidity\")\r\n |> drop(columns: [\"_field\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Humidty",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic",
+ "seriesBy": "last"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 4,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "area"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "max": 1500,
+ "min": 400,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "semi-dark-yellow",
+ "value": 700
+ },
+ {
+ "color": "semi-dark-red",
+ "value": 900
+ },
+ {
+ "color": "semi-dark-purple",
+ "value": 1200
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 13,
+ "w": 20,
+ "x": 0,
+ "y": 18
+ },
+ "id": 13,
+ "options": {
+ "legend": {
+ "calcs": [
+ "min",
+ "max",
+ "mean",
+ "lastNotNull"
+ ],
+ "displayMode": "table",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: max, createEmpty: false)\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "CO2",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineStyle": {
+ "fill": "solid"
+ },
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "celsius"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 20,
+ "x": 0,
+ "y": 31
+ },
+ "id": 9,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"temperature\")\r\n |> movingAverage(n: 10)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "temperature"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Temperature",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "humidity"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 20,
+ "x": 0,
+ "y": 39
+ },
+ "id": 12,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"humidity\")\r\n |> movingAverage(n: 10)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Humidity",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green"
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "pressurehpa"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 20,
+ "x": 0,
+ "y": 47
+ },
+ "id": 20,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"aranet_id\"] == \"${monitor_id}\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"pressure\")\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Pressure",
+ "type": "timeseries"
+ }
+ ],
+ "refresh": "5m",
+ "revision": 1,
+ "schemaVersion": 38,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": [
+ {
+ "current": {},
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "definition": "import \"influxdata/influxdb/v1\"\r\nv1.tagValues(\r\n bucket: \"co2monitors\",\r\n tag: \"aranet_id\",\r\n predicate: (r) => true\r\n)\r\n |> map(fn: (r) => ({ r with \r\n label: \r\n if r._value == \"1\" then \"Room x\" \r\n else r._value }))",
+ "hide": 0,
+ "includeAll": false,
+ "label": "CO2Monitor",
+ "multi": false,
+ "name": "monitor_id",
+ "options": [],
+ "query": "import \"influxdata/influxdb/v1\"\r\nv1.tagValues(\r\n bucket: \"co2monitors\",\r\n tag: \"aranet_id\",\r\n predicate: (r) => true\r\n)\r\n |> map(fn: (r) => ({ r with \r\n label: \r\n if r._value == \"1\" then \"Room x\" \r\n else r._value }))",
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 3,
+ "type": "query"
+ }
+ ]
+ },
+ "time": {
+ "from": "now/d+8h",
+ "to": "now/d-1d+16h"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ]
+ },
+ "timezone": "",
+ "title": "CO2 Monitor detail",
+ "uid": "XrrY7Rx7z",
+ "version": 5,
+ "weekStart": ""
+}
diff --git a/docker/grafana/dashboards/CO2 Monitors.json b/docker/grafana/dashboards/CO2 Monitors.json
new file mode 100644
index 0000000..5db13cb
--- /dev/null
+++ b/docker/grafana/dashboards/CO2 Monitors.json
@@ -0,0 +1,1303 @@
+{
+ "__inputs": [
+ {
+ "name": "DS_INFLUXDB",
+ "label": "InfluxDB",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "influxdb",
+ "pluginName": "InfluxDB"
+ }
+ ],
+ "__elements": {},
+ "__requires": [
+ {
+ "type": "panel",
+ "id": "gauge",
+ "name": "Gauge",
+ "version": ""
+ },
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "9.4.3"
+ },
+ {
+ "type": "datasource",
+ "id": "influxdb",
+ "name": "InfluxDB",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "stat",
+ "name": "Stat",
+ "version": ""
+ },
+ {
+ "type": "panel",
+ "id": "timeseries",
+ "name": "Time series",
+ "version": ""
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "datasource",
+ "uid": "grafana"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "max": 2000,
+ "min": 0,
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ },
+ {
+ "color": "semi-dark-purple",
+ "value": 1200
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 14,
+ "options": {
+ "orientation": "vertical",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "showThresholdLabels": false,
+ "showThresholdMarkers": true
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": " from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> last()\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [
+ 5
+ ],
+ "type": "moving_average"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "CO2",
+ "type": "gauge"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "max": 2000,
+ "min": 400,
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 7
+ },
+ "id": 7,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n|> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [
+ 5
+ ],
+ "type": "moving_average"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "CO2",
+ "transformations": [],
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 14
+ },
+ "id": 15,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> max()\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [],
+ "type": "max"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Max CO2",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [
+ {
+ "options": {
+ "0": {
+ "index": 0,
+ "text": "---"
+ }
+ },
+ "type": "value"
+ }
+ ],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ },
+ {
+ "color": "#EAB839",
+ "value": 700
+ },
+ {
+ "color": "light-red",
+ "value": 900
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 21
+ },
+ "id": 16,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> median()\r\n |> drop(columns: [\"_start\", \"_stop\", \"_field\", \"dev_id\"])\r\n// |> rename(columns: {\"_value\":\"co2\"})\r\n |> map(fn: (r) => ({ r with _time: v.timeRangeStop}))\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))\r\n",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ },
+ {
+ "params": [],
+ "type": "mean"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Median CO2",
+ "transformations": [],
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 1,
+ "mappings": [],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "celsius"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 24,
+ "x": 0,
+ "y": 28
+ },
+ "id": 10,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "area",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"temperature\")\r\n |> movingAverage(n: 10)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "temperature"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Temperature",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "humidity"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 36
+ },
+ "id": 11,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "area",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"humidity\")\r\n |> movingAverage(n: 10)\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Humidty",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "description": "",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "decimals": 0,
+ "mappings": [],
+ "noValue": "---",
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "semi-dark-green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "pressurehpa"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 43
+ },
+ "id": 20,
+ "options": {
+ "colorMode": "none",
+ "graphMode": "area",
+ "justifyMode": "center",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "",
+ "values": false
+ },
+ "text": {},
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"pressure\")\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Pressure",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic",
+ "seriesBy": "last"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "area"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "max": 1500,
+ "min": 400,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "semi-dark-yellow",
+ "value": 700
+ },
+ {
+ "color": "semi-dark-red",
+ "value": 900
+ },
+ {
+ "color": "semi-dark-purple",
+ "value": 1200
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 15,
+ "w": 24,
+ "x": 0,
+ "y": 50
+ },
+ "id": 13,
+ "options": {
+ "legend": {
+ "calcs": [
+ "min",
+ "max",
+ "mean",
+ "lastNotNull"
+ ],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> aggregateWindow(every: v.windowPeriod, fn: max, createEmpty: false)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "co2"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "CO2",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineStyle": {
+ "fill": "solid"
+ },
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 1,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "celsius"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 10,
+ "w": 24,
+ "x": 0,
+ "y": 65
+ },
+ "id": 9,
+ "options": {
+ "legend": {
+ "calcs": [
+ "min",
+ "max",
+ "mean",
+ "lastNotNull"
+ ],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"temperature\")\r\n |> movingAverage(n: 10)\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "temperature"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Temperature",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "humidity"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 10,
+ "w": 24,
+ "x": 0,
+ "y": 75
+ },
+ "id": 12,
+ "options": {
+ "legend": {
+ "calcs": [
+ "min",
+ "max",
+ "mean",
+ "lastNotNull"
+ ],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"humidity\")\r\n |> movingAverage(n: 10)\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Humidity",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 2,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "pressurehpa"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 10,
+ "w": 24,
+ "x": 0,
+ "y": 85
+ },
+ "id": 19,
+ "options": {
+ "legend": {
+ "calcs": [
+ "min",
+ "max",
+ "mean",
+ "lastNotNull"
+ ],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "alias": "$tag_dev_id",
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "groupBy": [
+ {
+ "params": [
+ "dev_id"
+ ],
+ "type": "tag"
+ }
+ ],
+ "measurement": "sensors",
+ "orderByTime": "ASC",
+ "policy": "default",
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"pressure\")\r\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A",
+ "resultFormat": "time_series",
+ "select": [
+ [
+ {
+ "params": [
+ "humidity"
+ ],
+ "type": "field"
+ }
+ ]
+ ],
+ "tags": []
+ }
+ ],
+ "title": "Pressure",
+ "type": "timeseries"
+ }
+ ],
+ "refresh": "5m",
+ "revision": 1,
+ "schemaVersion": 38,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now/d+8h",
+ "to": "now/d-1d+16h"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h"
+ ]
+ },
+ "timezone": "Pacific/Auckland",
+ "title": "CO2 Monitors",
+ "uid": "0GPg0J57k",
+ "version": 11,
+ "weekStart": "monday"
+}
\ No newline at end of file
diff --git a/docker/grafana/dashboards/CO2 state timeline.json b/docker/grafana/dashboards/CO2 state timeline.json
new file mode 100644
index 0000000..3fd3035
--- /dev/null
+++ b/docker/grafana/dashboards/CO2 state timeline.json
@@ -0,0 +1,258 @@
+{
+ "__inputs": [
+ {
+ "name": "DS_INFLUXDB",
+ "label": "InfluxDB",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "influxdb",
+ "pluginName": "InfluxDB"
+ }
+ ],
+ "__elements": {},
+ "__requires": [
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "9.4.3"
+ },
+ {
+ "type": "datasource",
+ "id": "influxdb",
+ "name": "InfluxDB",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "state-timeline",
+ "name": "State timeline",
+ "version": ""
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "datasource",
+ "uid": "grafana"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "custom": {
+ "fillOpacity": 70,
+ "lineWidth": 0,
+ "spanNulls": false
+ },
+ "mappings": [],
+ "max": 1500,
+ "min": 400,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "semi-dark-yellow",
+ "value": 700
+ },
+ {
+ "color": "semi-dark-orange",
+ "value": 900
+ },
+ {
+ "color": "semi-dark-red",
+ "value": 1200
+ }
+ ]
+ },
+ "unit": "ppm"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 15,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 2,
+ "options": {
+ "alignValue": "center",
+ "legend": {
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "mergeValues": true,
+ "rowHeight": 0.9,
+ "showValue": "never",
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "query": "from(bucket: \"co2monitors\")\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> drop(columns: [\"_field\", \"dev_id\"])\r\n\r\n |> aggregateWindow(\r\n every: ${agg_period},\r\n fn: ${agg_func},\r\n )\r\n |> map(fn: (r) => ({ r with _measurement: \"\" }))\r\n |> map(fn: (r) => ({ r with \r\n aranet_id: \r\n if r.aranet_id == \"10\" then \"Room x\" \r\n else r.aranet_id }))",
+ "refId": "A"
+ }
+ ],
+ "title": "CO2",
+ "type": "state-timeline"
+ }
+ ],
+ "refresh": "",
+ "revision": 1,
+ "schemaVersion": 38,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": [
+ {
+ "auto": false,
+ "auto_count": 30,
+ "auto_min": "10s",
+ "current": {
+ "selected": false,
+ "text": "1h",
+ "value": "1h"
+ },
+ "hide": 0,
+ "label": "aggregation period",
+ "name": "agg_period",
+ "options": [
+ {
+ "selected": false,
+ "text": "1m",
+ "value": "1m"
+ },
+ {
+ "selected": false,
+ "text": "5m",
+ "value": "5m"
+ },
+ {
+ "selected": false,
+ "text": "10m",
+ "value": "10m"
+ },
+ {
+ "selected": false,
+ "text": "30m",
+ "value": "30m"
+ },
+ {
+ "selected": true,
+ "text": "1h",
+ "value": "1h"
+ },
+ {
+ "selected": false,
+ "text": "6h",
+ "value": "6h"
+ },
+ {
+ "selected": false,
+ "text": "12h",
+ "value": "12h"
+ },
+ {
+ "selected": false,
+ "text": "1d",
+ "value": "1d"
+ }
+ ],
+ "query": "1m,5m,10m,30m,1h,6h,12h,1d",
+ "queryValue": "",
+ "refresh": 2,
+ "skipUrlSync": false,
+ "type": "interval"
+ },
+ {
+ "current": {
+ "selected": true,
+ "text": "median",
+ "value": "median"
+ },
+ "hide": 0,
+ "includeAll": false,
+ "label": "aggregation function",
+ "multi": false,
+ "name": "agg_func",
+ "options": [
+ {
+ "selected": false,
+ "text": "mean",
+ "value": "mean"
+ },
+ {
+ "selected": true,
+ "text": "median",
+ "value": "median"
+ },
+ {
+ "selected": false,
+ "text": "min",
+ "value": "min"
+ },
+ {
+ "selected": false,
+ "text": "max",
+ "value": "max"
+ }
+ ],
+ "query": "mean, median, min, max",
+ "queryValue": "",
+ "skipUrlSync": false,
+ "type": "custom"
+ }
+ ]
+ },
+ "time": {
+ "from": "now-30d",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "CO2 state timeline",
+ "uid": "f3V6jyUnk",
+ "version": 4,
+ "weekStart": ""
+}
diff --git a/docker/grafana/dashboards/Configuration.json b/docker/grafana/dashboards/Configuration.json
new file mode 100644
index 0000000..6aca8e1
--- /dev/null
+++ b/docker/grafana/dashboards/Configuration.json
@@ -0,0 +1,327 @@
+{
+ "__inputs": [
+ {
+ "name": "DS_INFLUXDB",
+ "label": "InfluxDB",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "influxdb",
+ "pluginName": "InfluxDB"
+ }
+ ],
+ "__elements": {},
+ "__requires": [
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "9.4.3"
+ },
+ {
+ "type": "datasource",
+ "id": "influxdb",
+ "name": "InfluxDB",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "stat",
+ "name": "Stat",
+ "version": ""
+ }
+ ],
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "datasource",
+ "uid": "grafana"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "text",
+ "value": null
+ }
+ ]
+ },
+ "unit": "none"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 17,
+ "x": 0,
+ "y": 0
+ },
+ "id": 5,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "/.*/",
+ "values": false
+ },
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "query": "from(bucket: \"co2monitors\")\r\n// |> range(start: -1y)\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"configuration\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"appVersion\")\r\n |> last()\r\n |> map(fn: (r) => ({\"\":r._value, dev_id:r.dev_id}))\r\n |> map(fn: (r) => ({ r with dev_id: \r\n if r.dev_id == \"10\" then \"Room x\" \r\n else r.dev_id }))",
+ "refId": "A"
+ }
+ ],
+ "title": "App version",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "fixed"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "dateTimeFromNow"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 17,
+ "x": 0,
+ "y": 4
+ },
+ "id": 10,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "/.*/",
+ "values": false
+ },
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "query": "from(bucket: \"co2monitors\")\r\n// |> range(start: -1y)\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensors\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"co2\")\r\n |> last()\r\n |> map(fn: (r) => ({\"\":r._time, dev_id:r.dev_id}))\r\n |> map(fn: (r) => ({ r with \r\n dev_id: \r\n if r.dev_id == \"10\" then \"Room x\" \r\n else r.dev_id }))",
+ "refId": "A"
+ }
+ ],
+ "title": "Last measurement",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "fixed"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "dateTimeFromNow"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 17,
+ "x": 0,
+ "y": 8
+ },
+ "id": 4,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "/.*/",
+ "values": false
+ },
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "query": "from(bucket: \"co2monitors\")\r\n// |> range(start: -1y)\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"configuration\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"appVersion\")\r\n |> last()\r\n |> map(fn: (r) => ({\"\":r._time, dev_id:r.dev_id}))\r\n |> map(fn: (r) => ({ r with \r\n dev_id: \r\n if r.dev_id == \"10\" then \"Room x\" \r\n else r.dev_id }))",
+ "refId": "A"
+ }
+ ],
+ "title": "Config refresh",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "fixed"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "dateTimeAsLocalNoDateIfToday"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 5,
+ "w": 17,
+ "x": 0,
+ "y": 12
+ },
+ "id": 3,
+ "options": {
+ "colorMode": "value",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "auto",
+ "reduceOptions": {
+ "calcs": [
+ "lastNotNull"
+ ],
+ "fields": "/.*/",
+ "values": false
+ },
+ "textMode": "value_and_name"
+ },
+ "pluginVersion": "9.4.3",
+ "targets": [
+ {
+ "datasource": {
+ "type": "influxdb",
+ "uid": "influxdb"
+ },
+ "query": "from(bucket: \"co2monitors\")\r\n// |> range(start: -1y)\r\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\r\n |> filter(fn: (r) => r[\"_measurement\"] == \"configuration\")\r\n |> filter(fn: (r) => r[\"_field\"] == \"appVersion\")\r\n |> last()\r\n |> map(fn: (r) => ({\"\":r._time, dev_id:r.dev_id}))\r\n |> map(fn: (r) => ({ r with \r\n dev_id: \r\n if r.dev_id == \"10\" then \"Room x\" \r\n else r.dev_id }))",
+ "refId": "A"
+ }
+ ],
+ "title": "Config refresh",
+ "type": "stat"
+ }
+ ],
+ "refresh": "5m",
+ "revision": 1,
+ "schemaVersion": 38,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": []
+ },
+ "time": {
+ "from": "now-30d",
+ "to": "now"
+ },
+ "timepicker": {
+ "refresh_intervals": [
+ "1m",
+ "5m",
+ "15m",
+ "30m",
+ "1h",
+ "2h",
+ "1d"
+ ]
+ },
+ "timezone": "",
+ "title": "Configuration",
+ "uid": "2lpRkwxnk",
+ "version": 3,
+ "weekStart": ""
+}
diff --git a/docker/grafana/grafana.ini b/docker/grafana/grafana.ini
new file mode 100644
index 0000000..9caea8e
--- /dev/null
+++ b/docker/grafana/grafana.ini
@@ -0,0 +1,1170 @@
+##################### Grafana Configuration Example #####################
+#
+# Everything has defaults so you only need to uncomment things you want to
+# change
+
+# possible values : production, development
+;app_mode = production
+
+# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty
+;instance_name = ${HOSTNAME}
+
+# force migration will run migrations that might cause dataloss
+;force_migration = false
+
+#################################### Paths ####################################
+[paths]
+# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
+;data = /var/lib/grafana
+
+# Temporary files in `data` directory older than given duration will be removed
+;temp_data_lifetime = 24h
+
+# Directory where grafana can store logs
+;logs = /var/log/grafana
+
+# Directory where grafana will automatically scan and look for plugins
+;plugins = /var/lib/grafana/plugins
+
+# folder that contains provisioning config files that grafana will apply on startup and while running.
+;provisioning = /var/lib/grafana/conf/provisioning
+
+#################################### Server ####################################
+[server]
+# Protocol (http, https, h2, socket)
+;protocol = http
+
+# The ip address to bind to, empty will bind to all interfaces
+;http_addr =
+
+# The http port to use
+;http_port = 3000
+
+# The public facing domain name used to access grafana from a browser
+;domain = localhost
+
+# Redirect to correct domain if host header does not match domain
+# Prevents DNS rebinding attacks
+;enforce_domain = false
+
+# The full public facing url you use in browser, used for redirects and emails
+# If you use reverse proxy and sub path specify full url (with sub path)
+;root_url = %(protocol)s://%(domain)s:%(http_port)s/
+
+# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons.
+;serve_from_sub_path = false
+
+# Log web requests
+;router_logging = false
+
+# the path relative working path
+;static_root_path = public
+
+# enable gzip
+;enable_gzip = false
+
+# https certs & key file
+;cert_file =
+;cert_key =
+
+# Unix socket path
+;socket =
+
+# CDN Url
+;cdn_url =
+
+# Sets the maximum time using a duration format (5s/5m/5ms) before timing out read of an incoming request and closing idle connections.
+# `0` means there is no timeout for reading the request.
+;read_timeout = 0
+
+#################################### Database ####################################
+[database]
+# You can configure the database connection by specifying type, host, name, user and password
+# as separate properties or as on string using the url properties.
+
+# Either "mysql", "postgres" or "sqlite3", it's your choice
+;type = sqlite3
+;host = 127.0.0.1:3306
+;name = grafana
+;user = root
+# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
+;password =
+
+# Use either URL or the previous fields to configure the database
+# Example: mysql://user:secret@host:port/database
+;url =
+
+# For "postgres" only, either "disable", "require" or "verify-full"
+;ssl_mode = disable
+
+# Database drivers may support different transaction isolation levels.
+# Currently, only "mysql" driver supports isolation levels.
+# If the value is empty - driver's default isolation level is applied.
+# For "mysql" use "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ" or "SERIALIZABLE".
+;isolation_level =
+
+;ca_cert_path =
+;client_key_path =
+;client_cert_path =
+;server_cert_name =
+
+# For "sqlite3" only, path relative to data_path setting
+;path = grafana.db
+
+# Max idle conn setting default is 2
+;max_idle_conn = 2
+
+# Max conn setting default is 0 (mean not set)
+;max_open_conn =
+
+# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours)
+;conn_max_lifetime = 14400
+
+# Set to true to log the sql calls and execution times.
+;log_queries =
+
+# For "sqlite3" only. cache mode setting used for connecting to the database. (private, shared)
+;cache_mode = private
+
+# For "mysql" only if lockingMigration feature toggle is set. How many seconds to wait before failing to lock the database for the migrations, default is 0.
+;locking_attempt_timeout_sec = 0
+
+################################### Data sources #########################
+[datasources]
+# Upper limit of data sources that Grafana will return. This limit is a temporary configuration and it will be deprecated when pagination will be introduced on the list data sources API.
+;datasource_limit = 5000
+
+#################################### Cache server #############################
+[remote_cache]
+# Either "redis", "memcached" or "database" default is "database"
+;type = database
+
+# cache connectionstring options
+# database: will use Grafana primary database.
+# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=0,ssl=false`. Only addr is required. ssl may be 'true', 'false', or 'insecure'.
+# memcache: 127.0.0.1:11211
+;connstr =
+
+#################################### Data proxy ###########################
+[dataproxy]
+
+# This enables data proxy logging, default is false
+;logging = false
+
+# How long the data proxy waits to read the headers of the response before timing out, default is 30 seconds.
+# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set.
+;timeout = 30
+
+# How long the data proxy waits to establish a TCP connection before timing out, default is 10 seconds.
+;dialTimeout = 10
+
+# How many seconds the data proxy waits before sending a keepalive probe request.
+;keep_alive_seconds = 30
+
+# How many seconds the data proxy waits for a successful TLS Handshake before timing out.
+;tls_handshake_timeout_seconds = 10
+
+# How many seconds the data proxy will wait for a server's first response headers after
+# fully writing the request headers if the request has an "Expect: 100-continue"
+# header. A value of 0 will result in the body being sent immediately, without
+# waiting for the server to approve.
+;expect_continue_timeout_seconds = 1
+
+# Optionally limits the total number of connections per host, including connections in the dialing,
+# active, and idle states. On limit violation, dials will block.
+# A value of zero (0) means no limit.
+;max_conns_per_host = 0
+
+# The maximum number of idle connections that Grafana will keep alive.
+;max_idle_connections = 100
+
+# How many seconds the data proxy keeps an idle connection open before timing out.
+;idle_conn_timeout_seconds = 90
+
+# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false.
+;send_user_header = false
+
+# Limit the amount of bytes that will be read/accepted from responses of outgoing HTTP requests.
+;response_limit = 0
+
+# Limits the number of rows that Grafana will process from SQL data sources.
+;row_limit = 1000000
+
+#################################### Analytics ####################################
+[analytics]
+# Server reporting, sends usage counters to stats.grafana.org every 24 hours.
+# No ip addresses are being tracked, only simple counters to track
+# running instances, dashboard and error counts. It is very helpful to us.
+# Change this option to false to disable reporting.
+;reporting_enabled = true
+
+# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs
+;reporting_distributor = grafana-labs
+
+# Set to false to disable all checks to https://grafana.com
+# for new versions of grafana. The check is used
+# in some UI views to notify that a grafana update exists.
+# This option does not cause any auto updates, nor send any information
+# only a GET request to https://raw.githubusercontent.com/grafana/grafana/main/latest.json to get the latest version.
+;check_for_updates = true
+
+# Set to false to disable all checks to https://grafana.com
+# for new versions of plugins. The check is used
+# in some UI views to notify that a plugin update exists.
+# This option does not cause any auto updates, nor send any information
+# only a GET request to https://grafana.com to get the latest versions.
+;check_for_plugin_updates = true
+
+# Google Analytics universal tracking code, only enabled if you specify an id here
+;google_analytics_ua_id =
+
+# Google Tag Manager ID, only enabled if you specify an id here
+;google_tag_manager_id =
+
+# Rudderstack write key, enabled only if rudderstack_data_plane_url is also set
+;rudderstack_write_key =
+
+# Rudderstack data plane url, enabled only if rudderstack_write_key is also set
+;rudderstack_data_plane_url =
+
+# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set
+;rudderstack_sdk_url =
+
+# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
+;rudderstack_config_url =
+
+# Controls if the UI contains any links to user feedback forms
+;feedback_links_enabled = true
+
+#################################### Security ####################################
+[security]
+# disable creation of admin user on first start of grafana
+;disable_initial_admin_creation = false
+
+# default admin user, created on startup
+;admin_user = admin
+
+# default admin password, can be changed before first start of grafana, or in profile settings
+;admin_password = admin
+
+# used for signing
+;secret_key = SW2YcwTIb9zpOOhoPsMm
+
+# current key provider used for envelope encryption, default to static value specified by secret_key
+;encryption_provider = secretKey.v1
+
+# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1
+;available_encryption_providers =
+
+# disable gravatar profile images
+;disable_gravatar = false
+
+# data source proxy whitelist (ip_or_domain:port separated by spaces)
+;data_source_proxy_whitelist =
+
+# disable protection against brute force login attempts
+;disable_brute_force_login_protection = false
+
+# set to true if you host Grafana behind HTTPS. default is false.
+;cookie_secure = false
+
+# set cookie SameSite attribute. defaults to `lax`. can be set to "lax", "strict", "none" and "disabled"
+;cookie_samesite = lax
+
+# set to true if you want to allow browsers to render Grafana in a ,