This commit is contained in:
Björn Ellensohn 2024-02-06 19:51:49 +01:00
parent eaa5c056de
commit 5ae5a102c0
5 changed files with 701 additions and 15 deletions

View File

@ -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. 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. 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. 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://<ESP_IP>:80`. 6. Control the ESP32 via the webserver at `http://<ESP_IP>:80`.
You can obtain the ESP32 IP address from the serial console. 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 ### Setup your services
Install the latest version of Docker and Docker Compose: Install the latest version of Docker and Docker Compose:
[https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/) [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/)
Start the services via: Start the services via:
```shell ```shell
docker compose up -d docker compose up -d
@ -53,9 +54,9 @@ docker compose up -d
Now you can access Grafana and InfluxDB via the webgui. 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' . 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. 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: 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. 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) ![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://<ESP_IP>:80`. 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://<ESP_IP>: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
![Grafana Dashboard](resources/dashboard.png) ![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 ##### Webserver
<img src="resources/webserver.png" alt="ESP32 Webserver" title="ESP32 Webserver" width="350" /> <img src="resources/webserver.png" alt="ESP32 Webserver" title="ESP32 Webserver" width="350" />
### Further information
For more information check out these links:
https://grafana.com/
https://www.influxdata.com/
Explore the code, contribute, and provide feedback. Explore the code, contribute, and provide feedback.

View File

@ -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": ""
}

View File

@ -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

View File

@ -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#

View File

@ -5,16 +5,16 @@ services:
container_name: influxdb-test container_name: influxdb-test
image: influxdb:2.7.1-alpine image: influxdb:2.7.1-alpine
ports: ports:
- '8087:8086' # InfluxDB wird am Server unter Port 8087 bereitgestellt. - '8086:8086' # InfluxDB wird am Server unter Port 8086 bereitgestellt.
volumes: volumes:
- influxdb-data:/var/lib/influxdb2 # Docker Volume: Hier werden die Daten permanent gespeichert. - influxdb-data:/var/lib/influxdb2 # Docker Volume: Hier werden die Daten permanent gespeichert.
environment: environment:
- DOCKER_INFLUXDB_INIT_MODE=setup - DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=influxUser - DOCKER_INFLUXDB_INIT_USERNAME=influxuser
- DOCKER_INFLUXDB_INIT_PASSWORD=influxUserPW # Sollte geaendert werden. - DOCKER_INFLUXDB_INIT_PASSWORD=influxpw # Sollte geaendert werden.
- DOCKER_INFLUXDB_INIT_ORG=org-uni - DOCKER_INFLUXDB_INIT_ORG=org-uni
- DOCKER_INFLUXDB_INIT_BUCKET=bucket-digitalisierung - 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). - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=8gs8r6ZZp@%EGnR@xRpJ@d4sH2M%5m8# # (optional) admin-token definieren (sollte geaendert werden).
restart: unless-stopped restart: unless-stopped
@ -25,17 +25,17 @@ services:
depends_on: depends_on:
- influxdb - influxdb
environment: environment:
- GF_SECURITY_ADMIN_USER=gfUser - GF_SECURITY_ADMIN_USER=gfuser
- GF_SECURITY_ADMIN_PASSWORD=gfUserPW # Sollte geaendert werden. - GF_SECURITY_ADMIN_PASSWORD=gfpw # Sollte geaendert werden.
- GF_INSTALL_PLUGINS= - GF_INSTALL_PLUGINS=
- GF_SERVER_ROOT_URL="https://gf.bjoernellens1.com" # Dashboard derzeit unter dieser Subdomain erreichbar.
- GF_SERVER_DOMAIN=gf.bjoernellens1.com
links: links:
- influxdb - influxdb
ports: ports:
- '3002:3000' # Grafana wird am Server unter Port 3002 bereitgestellt. - '3000:3000' # Grafana wird am Server unter Port 3000 bereitgestellt.
volumes: volumes:
- grafana_data:/var/lib/grafana # Docker Volume: Hier werden die Daten permanent gespeichert. - 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. volumes: # Die Docker Volumes muessen hier definiert werden, werden dann automatisch mit dem Stack erstellt.
grafana_data: {} grafana_data: {}