From 5ae5a102c0d4d2e2ffa9b25e8446886d4cdbbcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ellensohn?= Date: Tue, 6 Feb 2024 19:51:49 +0100 Subject: [PATCH] update --- README.md | 20 +- config/grafana/dashboards/dashboard.json | 653 +++++++++++++++++++++ config/grafana/dashboards/dashboard.yml | 11 + config/grafana/datasources/datasource.yaml | 14 + docker-compose.yml | 18 +- 5 files changed, 701 insertions(+), 15 deletions(-) create mode 100644 config/grafana/dashboards/dashboard.json create mode 100644 config/grafana/dashboards/dashboard.yml create mode 100644 config/grafana/datasources/datasource.yaml diff --git a/README.md b/README.md index d0ac51d..8374a06 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This repository contains the source code for our university group project focuse 2. Open this folder with Visual Studio Code and install the PlatformIO plugin. 3. Rename `secrets.h.example` to `secrets.h` and fill in your credentials. 4. Flash ESP32 with the code. Connect the INA219 module according to the schematics and power up the ESP32. -5. The ESP32 will connect to your WiFi and start sending data to the InfluxDB. InfluxDB webgui is available at [http://localhost:8087](http://localhost:8087). You can now start the Grafana dashboard and connect it to the InfluxDB. The Grafana dashboard is available at [http://localhost:3002](http://localhost:3002). +5. The ESP32 will connect to your WiFi and start sending data to the InfluxDB. InfluxDB webgui is available at [http://localhost:8086](http://localhost:8086). You can now start the Grafana dashboard and connect it to the InfluxDB. The Grafana dashboard is available at [http://localhost:3000](http://localhost:3000). 6. Control the ESP32 via the webserver at `http://:80`. You can obtain the ESP32 IP address from the serial console. @@ -46,6 +46,7 @@ git clone https://github.com/bjoernellens1/ESP32-PowerGuard.git ### Setup your services Install the latest version of Docker and Docker Compose: [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/) + Start the services via: ```shell docker compose up -d @@ -53,9 +54,9 @@ docker compose up -d Now you can access Grafana and InfluxDB via the webgui. -The Grafana dashboard is available at [http://localhost:3002](http://localhost:3002). +The Grafana dashboard is available at [http://localhost:3000](http://localhost:3000). -InfluxDB webgui is available at [http://localhost:8087](http://localhost:8087). +InfluxDB webgui is available at [http://localhost:8086](http://localhost:8086). Having the services running, it is time to start the setup wizard in InfluxDB. Login with username 'influxUser' and password 'influxUserPW' . On the welcome page you will see the Ardino setup tutorial. Click on the 'Arduino' button and follow the instructions. Here you will obtain parameters needed in the next step. @@ -73,10 +74,10 @@ Open this folder in Visual Studio Code. The PlatformIO welcome page will open au Then you need to change some files to include your configuration: -Rename `secrets.h.example` to `secrets.h` and fill in your credentials. INFLUXDB_TOKEN is the token you obtained in the previous step. INFLUXDB_ORG is the organization name you chose. INFLUXDB_BUCKET is the bucket name you chose. INFLUXDB_URL is the URL of your InfluxDB instance. In our case we are hosting it locally, so we need to fill in the PCs IP Adress followed by the InfluxDB port, for instance: +Rename `secrets.h.example` to `secrets.h` and fill in your credentials. INFLUXDB_TOKEN is the token you obtained in the previous step. INFLUXDB_ORG is the organization name you chose. INFLUXDB_BUCKET is the bucket name you chose. INFLUXDB_URL is the URL of your InfluxDB instance. In our case we are hosting it locally, so we need to fill in the PC's IP Adress followed by the InfluxDB port, for instance: ``` -INFLUXDB_URL = "http://192.168.1.100:8087" +INFLUXDB_URL = "http://192.168.1.100:8086" ``` WIFI_SSID and WIFI_PASS are your WiFi credentials. @@ -87,7 +88,7 @@ Now you can click on the upload button to flash the ESP. ![Upload Button](resources/upload.png) Use the serial monitor to see the output of the ESP. You will see the IP address of the ESP. You can now access the webserver at `http://:80`. -Also, the ESP should now be able to send data to the database. Now the data should appear in the database and you should be greeted be able to configure these views: +Also, the ESP should now be able to send data to the database. Now the data should appear in the database. For your convenience, the Grafana dashboard was preconfigured in the config/grafana directory so you should already see this: ##### Grafana ![Grafana Dashboard](resources/dashboard.png) @@ -95,6 +96,13 @@ Also, the ESP should now be able to send data to the database. Now the data shou ##### Webserver ESP32 Webserver +### Further information +For more information check out these links: + + https://grafana.com/ + + https://www.influxdata.com/ + Explore the code, contribute, and provide feedback. diff --git a/config/grafana/dashboards/dashboard.json b/config/grafana/dashboards/dashboard.json new file mode 100644 index 0000000..d00edf1 --- /dev/null +++ b/config/grafana/dashboards/dashboard.json @@ -0,0 +1,653 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "liveNow": true, + "panels": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 7, + "min": 3, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "light-green", + "value": 4 + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "orange", + "value": 5.5 + }, + { + "color": "red", + "value": 6 + } + ] + }, + "unit": "volt" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 5, + "options": { + "minVizHeight": 200, + "minVizWidth": 200, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"busVoltage\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Voltage", + "type": "gauge" + }, + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 7, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "light-green", + "value": 4 + }, + { + "color": "yellow", + "value": 5 + }, + { + "color": "orange", + "value": 5.5 + }, + { + "color": "red", + "value": 6 + } + ] + }, + "unit": "mamp" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 6, + "options": { + "minVizHeight": 200, + "minVizWidth": 200, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"current\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Current", + "type": "gauge" + }, + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "max": 30, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "light-green", + "value": 10 + }, + { + "color": "yellow", + "value": 20 + }, + { + "color": "orange", + "value": 25 + }, + { + "color": "red", + "value": 30 + } + ] + }, + "unit": "watt" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 7, + "options": { + "minVizHeight": 200, + "minVizWidth": 200, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.2.3", + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"power\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Power", + "type": "gauge" + }, + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-blues" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "volt" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"busVoltage\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Voltage", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "watth" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"totalEnergy\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Total Energy", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "fixed" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mamp" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"current\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Current", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "description": "Current Power draw in Watts", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "watt" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "influxdb", + "uid": "InfluxDB_v2_Flux" + }, + "query": "from(bucket: \"bucket-digitalisierung\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data\")\n |> filter(fn: (r) => r[\"_field\"] == \"power\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> yield(name: \"last\")", + "refId": "A" + } + ], + "title": "Power", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Projekt Digitalisierung", + "uid": "ad5b79b9-0977-4c26-853d-63dc408b9544", + "version": 7, + "weekStart": "" + } \ No newline at end of file diff --git a/config/grafana/dashboards/dashboard.yml b/config/grafana/dashboards/dashboard.yml new file mode 100644 index 0000000..4ae559e --- /dev/null +++ b/config/grafana/dashboards/dashboard.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: +- name: 'Projekt Digitalisierung' + orgId: 1 + folder: '' + type: file + disableDeletion: false + editable: true + options: + path: /etc/grafana/provisioning/dashboards \ No newline at end of file diff --git a/config/grafana/datasources/datasource.yaml b/config/grafana/datasources/datasource.yaml new file mode 100644 index 0000000..ea31fcb --- /dev/null +++ b/config/grafana/datasources/datasource.yaml @@ -0,0 +1,14 @@ +apiVersion: 1 + +datasources: + - name: InfluxDB_v2_Flux + type: influxdb + access: proxy + url: http://influxdb:8086 + jsonData: + version: Flux + organization: org-uni + defaultBucket: bucket-digitalisierung + tlsSkipVerify: true + secureJsonData: + token: 8gs8r6ZZp@%EGnR@xRpJ@d4sH2M%5m8# \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index c04a4cc..b80f555 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,16 +5,16 @@ services: container_name: influxdb-test image: influxdb:2.7.1-alpine ports: - - '8087:8086' # InfluxDB wird am Server unter Port 8087 bereitgestellt. + - '8086:8086' # InfluxDB wird am Server unter Port 8086 bereitgestellt. volumes: - influxdb-data:/var/lib/influxdb2 # Docker Volume: Hier werden die Daten permanent gespeichert. environment: - DOCKER_INFLUXDB_INIT_MODE=setup - - DOCKER_INFLUXDB_INIT_USERNAME=influxUser - - DOCKER_INFLUXDB_INIT_PASSWORD=influxUserPW # Sollte geaendert werden. + - DOCKER_INFLUXDB_INIT_USERNAME=influxuser + - DOCKER_INFLUXDB_INIT_PASSWORD=influxpw # Sollte geaendert werden. - DOCKER_INFLUXDB_INIT_ORG=org-uni - DOCKER_INFLUXDB_INIT_BUCKET=bucket-digitalisierung - - DOCKER_INFLUXDB_INIT_RETENTION=1w # (optional) data retention: Wann werden Daten geloescht? + #- DOCKER_INFLUXDB_INIT_RETENTION=1w # (optional) data retention: Wann werden Daten geloescht? - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=8gs8r6ZZp@%EGnR@xRpJ@d4sH2M%5m8# # (optional) admin-token definieren (sollte geaendert werden). restart: unless-stopped @@ -25,17 +25,17 @@ services: depends_on: - influxdb environment: - - GF_SECURITY_ADMIN_USER=gfUser - - GF_SECURITY_ADMIN_PASSWORD=gfUserPW # Sollte geaendert werden. + - GF_SECURITY_ADMIN_USER=gfuser + - GF_SECURITY_ADMIN_PASSWORD=gfpw # Sollte geaendert werden. - GF_INSTALL_PLUGINS= - - GF_SERVER_ROOT_URL="https://gf.bjoernellens1.com" # Dashboard derzeit unter dieser Subdomain erreichbar. - - GF_SERVER_DOMAIN=gf.bjoernellens1.com links: - influxdb ports: - - '3002:3000' # Grafana wird am Server unter Port 3002 bereitgestellt. + - '3000:3000' # Grafana wird am Server unter Port 3000 bereitgestellt. volumes: - grafana_data:/var/lib/grafana # Docker Volume: Hier werden die Daten permanent gespeichert. + - ./config/grafana:/etc/grafana/provisioning/ + - ./config/grafana/dashboards/dashboard.json:/usr/share/grafana/public/dashboards/home.json volumes: # Die Docker Volumes muessen hier definiert werden, werden dann automatisch mit dem Stack erstellt. grafana_data: {}