Moved the documentation into docs folder and removed folders that should not belont to this repository

This commit is contained in:
simonox 2023-09-16 12:49:44 +02:00
parent 094c5ce682
commit 3c75579102
97 changed files with 337 additions and 710 deletions

View file

@ -1,38 +0,0 @@
# Grafana
Grafana is an open source analytics and interactive visualization tool. It provides charts, graphs, and alerts for the web when connected to supported data sources.
As a visualization tool, Grafana is a popular component in monitoring stacks, often used in combination with time series databases such as InfluxDB.
## Connection
To connect Grafana to our Influx-DB, you have to create a data source.
The `URL`of our InfluxDB is `http://influxdb:8086`.
In InfluxDB you have to create a `token` to connect: [Load Data -> API Tokens](http://localhost:8086/orgs/721027680173bf2f/load-data/tokens).
![Influx Create Token](../flow/docs/images/influx-create-token.png)
You can use this token to [create a connection from Grafana to Influx-DB](http://localhost:3000/datasources/).
![Connection](./docs/images/database-connection.png)
After having a connection to a database you can easily create an own dashboard in Grafana.
Here's the demo snippet (directly copyied from Influx Data Explorer) and the screen shot.
```
from(bucket: "test")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "msg")
|> filter(fn: (r) => r["_field"] == "value")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
![Example Dashboard](./docs/images/grafana-example-dashboard.png)
## CSV Import
See [CSV Import](./docs/csv-import.md).

View file

@ -1,30 +0,0 @@
# CSV Import
## Grafana
In Grafana there is a [csv-datasource plugin](https://grafana.github.io/grafana-csv-datasource/). This plug lets you visualize data from any URL that returns CSV data, such as REST APIs or static file servers. You can even load data from a local file path. But it is *not* importing CSV from Grafana into a data source (like InfluxDB) or uploading CSV data to a local file system.
> For visualizing CSV data this is enough. Why should you duplicate data if the true data source is a CSV file located somewhere in the internet. If the CSV is not online, this might be another story.
I added this plugin to our Grafana installation, so it's ready to be used.
> I just mounted the whole [Grafana directory](../grafana/) into our Docker-Compose setup. Maybe we have to come up with a better solution.
![Mounted directory](./images/mounted-grafana-directory.png)
Garafana is running on [localhost on port 3000 with credentials admin:admin](http://localhost:3000). So let's get there to add the CSV file as a usable data source.
> I added the CSV file to this repository and mounted it into our Docker-Compose setup. So the CSV file is also available in Grafana. Maybe we have to come up with a better solution..
As the CSV is reachable by Grafana, you can create a data source, there.
![Mounting a CSV file](./images/grafana-csv-data-source.png)
> grafana.ini is also mounted from [this repository](../grafana.ini). So local data mode is enabled.
Whith Grafana having access to data in the CSV file, it's easy to access this data to create a dashboard.
![Using CSV data](./images/grafana-csv-data.png)
![Defining types](./images/grafana-csv-data-type.png)
![Two boards in Grafana](./images/grafana-two-boards.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -0,0 +1,37 @@
{
"levels": [
{},
{
"m": 33554432,
"k": 6
},
{
"m": 33554432,
"k": 6
},
{
"m": 67108864,
"k": 6
},
{
"m": 134217728,
"k": 6
},
{
"m": 268435456,
"k": 6
},
{
"m": 536870912,
"k": 6
},
{
"m": 1073741824,
"k": 6
}
],
"files": [
"L0-00000001.tsl"
],
"version": 1
}

View file

@ -1,8 +0,0 @@
#!/bin/sh
echo Publishing random values to topic '/iot-platform/energy-monitor/test-device/watt'
while true
do
mosquitto_pub -h localhost -p 1883 -t '/iot-platform/energy-monitor/test-device/watt' -m $((1 + $RANDOM % 10 * 500))
printf '%s' "."
sleep 1
done

View file

@ -1,26 +0,0 @@
/*
SCT-013 Sensor - Power meassurement, based on Thomas Edlinger's code for "www.edistechlab.com"
Required libraries (Tools -> manage libraries)
- EmonLib libary V1.1.0 by OpenEnergyMonitor
Based on EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3
*/
#include "EmonLib.h"
EnergyMonitor emon1;
const byte current1Pin = A1; // ADC-PIN
const byte voltage = 230; // Power voltage in Europe = 230 V
void setup() {
Serial.begin(115200);
analogReadResolution(ADC_BITS); // activate 12 Bit resolution for our ESP32
emon1.current(current1Pin, 8); // Pin and Calibration
}
void loop() {
double Irms = emon1.calcIrms(1480);
Serial.print(Irms*voltage);
Serial.print(" Watt - ");
Serial.print(Irms);
Serial.println(" Ampere");
delay(1000);
}

View file

@ -1,115 +0,0 @@
/*
Required libraries (Tools -> manage libraries)
- EmonLib@1.1.0
- PubSubClient@2.8.0
- WiFi.h - esp32 Wifi support
*/
#include <stdlib.h>
#include <EmonLib.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include "environment.h" // put your credentials and configuration in, here
// sensor
EnergyMonitor emon1;
const byte current1Pin = A1; // ADC-PIN
const byte voltage = 230; // Power voltage in Europe = 230 V
// refrences from environment.h
const char* ssid = secrect_ssid;
const char* password = secret_password;
const char* mqttServer = mqtt_server;
const int mqttPort = mqtt_port;
const char* mqttPrefix = mqtt_prefix;
// wifi and MQTT
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void setup() {
Serial.begin(115200);
Serial.setTimeout(500);
setup_energy_sensor();
setup_wifi();
setup_mqtt();
}
void setup_energy_sensor() {
analogReadResolution(ADC_BITS); // activate 12 Bit resolution for our ESP32
emon1.current(current1Pin, 8); // Pin and Calibration
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void setup_mqtt() {
client.setServer(mqttServer, mqttPort);
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
//Once connected, publish an announcement...
client.publish(concat(mqttPrefix, "/status"), "online");
// ... and resubscribe
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
char* concat(const char* str1, const char* str2) {
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
void loop() {
// get values
double irms = emon1.calcIrms(1480);
double power = irms * voltage;
// debug, print out on serial
Serial.print(power);
Serial.print(" Watt - ");
Serial.print(irms);
Serial.println(" Ampere");
// convert double to char array for MQTT
char powerArray[10];
snprintf(powerArray, 10, "%f", power);
char irmsArray[10];
snprintf(irmsArray, 10, "%f", irms);
// publish values
client.publish(concat(mqttPrefix, "/watt"), powerArray);
client.publish(concat(mqttPrefix, "/ampere"), irmsArray);
// wait a second
delay(1000);
}

View file

@ -1,6 +0,0 @@
// Replace with your network credentials
#define secrect_ssid "Guest"
#define secret_password "guestguest"
#define mqtt_server "192.168.1.233"
#define mqtt_port 1883
#define mqtt_prefix "/iot-platform/energy-monitor/test-device"

View file

@ -1,151 +0,0 @@
# Energy Monitor
Our energy monitor is based on the openenergymonitor.org project (Licence GNU GPL V3).
It uses our HelTec Wireless Stick. This - of course - can be replaced by a cheaper ESP32 module.
Power Measurement is done by a SCT013 clamp (100A:50mA).
## Build the hardware
### Used materials
* ESP32 module (e.g. Heltec Wireless Stick)
* 3 x SCT-013-100 (100 A), see: http://openenergymonitor.org/emon/node/156
* 6 x 10 kOhm Resistors 1/4 W
* 1 x 22 Ohm Resistor 1/4 W (TODO: I am using a 47 Ohm Resistor to be replaced)
* 3 x 10 uF Elko 10 V
* 3 x 3,5 mm audio jack connector
### PinOut
![PinOut](https://resource.heltec.cn/download/Wireless_Stick_V3/HTIT-WS_V3.png "PinOut")
We use A1, A2 and A3 because they are free (most ADCs are already used on the HelTec Board)
### Sensors
The SCT-013 sensors are small current transformers (SCT). They have a ferromagnetic core that can be opened and in which we can enclose our conductor. This conductor is the primary winding and the secondary winding is fixed in the sensor and can have 2000 turns. This gives us a ratio of 1:2000 as an example.
When AC current flows through the conductor, a magnetic flux is generated in the ferromagnetic core, which in turn generates an electric current in the secondary winding.
I could not meassure "small" power consumptions (like a LED lamp or a light stripe, as the magnetix flux in the ferromagnet core seems to be too small).
![clamp on wire](./docs/images/clamp1.jpeg "clamp on a wire")
I was able to measure high loads (like a heater the can be switched between 1 kW and 2 kW).
![heater](./docs/images/example-heater.png "serial out of a heater")
Make sure the clamp is *always positioned towards the consumer*, otherwise it does *not* work. There is a small arrow on the case.
![point the clamp](./docs/images/clamp2.jpeg "point the clamp")
> Attention: I could not measure any meaningful values on the "cable". I had to go to the wire.
![cable](./docs/images/clamp3.jpeg "use the clamp on the wire, not on the cable")
### Breadboard
Let's start with a simple breadboard layout.
![Breadboard](./docs/images/breadboard.png "breakboard layout")
![Photo of breadboard](./docs/images/photo-breadboard.jpeg "photo of breadboard")
To understand this, have a look at this plan:
![Plan](./docs/images/plan.png "plan")
R1 & R2 are a voltage divider that provides the 1.65 V source. We use 10 kΩ for mains powered monitors. If we want to run on batteries, we have to choose differnt ones (like 470 kΩ resistors to keep the power consumption to a minimum).
Capacitor C1 has a low reactance - a few hundred ohms - and provides a path for the alternating current to bypass the resistor. A value of 10 μF is suitable.
R3 is the burden resistor. Ideal burden would be 19 Ω. As this is not a common value, you could choose 18 Ω or 22 Ω (I am still using a 47 Ω restistor, that has to be replaced).
See the Fritzing file for [details](./energy-monitor/energy-monitor.fzz).
## Code
### Print to serial out
Start with a simple code that just prints the values. The code is quite simple, as we can use the existing *[EmonLib libary V1.1.0 by OpenEnergyMonitor](https://docs.openenergymonitor.org/electricity-monitoring/ct-sensors/)*.
[Check out the small amount of code to print the values to serial out.](./01-energy-monitor-serial-out/) This piece of code is based on on Thomas Edlinger's code for [Edi's Tech Lab](https://www.edistechlab.com).
The only interesting part is this line:
```C
emon1.current(current1Pin, 8); // Pin and Calibration
```
The [calibration](https://docs.openenergymonitor.org/electricity-monitoring/ctac/calibration.html) value "8" was done with a Fluke multimeter (and maybe a not so ideal burden resistor).
The code just prints the current power consumption to serial out:
```
16:28:18.915 -> 2853.16 Watt - 12.41 Ampere
16:28:19.998 -> 2854.63 Watt - 12.41 Ampere
16:28:21.119 -> 2850.93 Watt - 12.40 Ampere
16:28:22.207 -> 1702.19 Watt - 7.40 Ampere
16:28:23.289 -> 400.62 Watt - 1.74 Ampere
16:28:24.367 -> 94.42 Watt - 0.41 Ampere
```
### Post to MQTT
#### Boot up MQTT
First, boot your local server infrastructure:
```sh
docker-compose --file software/container/docker-compose.yml up
```
#### Credentials
To connect to your Wifi and access your MQTT server you have to add this to an `environment` [header file](./02-energy-monitor-mqtt/environment.h):
```C
// Replace with your network credentials
#define secrect_ssid "Guest"
#define secret_password "guestguest"
#define mqtt_server "192.168.2.103"
#define mqtt_port 1883
#define mqtt_prefix "/iot-platform/energy-monitor/test-device"
```
The `mqtt_server` in tis example posts to my local IP adress. The Wifi network is a `Guest` network I just created for this test.
The `mqtt_prefix` should be different per device, as this is the topic prefix used to identify the device.
### Testing
You can subscribe to your local MQTT server and subscribe to all or just the interesting topics:
```sh
mosquitto_sub -h localhost -t '#' -p 1883 #all
mosquitto_sub -h localhost -t '/iot-platform/energy-monitor/test-device/ampere' -p 1883 #current
mosquitto_sub -h localhost -t '/iot-platform/energy-monitor/test-device/watt' -p 1883 #power
```
### Interesting code blocks
Posting to MQTT is quite simple. After setting up Wifi and connection to the MQTT server, it's just a few lines of code:
```C
client.publish(concat(mqttPrefix, "/watt"), powerArray);
client.publish(concat(mqttPrefix, "/ampere"), irmsArray);
```
Have a look at the complete [example](./02-energy-monitor-mqtt/).
## Simulator
If you just need random inputs (without using the actual hardware), you can simply modify my short [shell script](./00-simulator/).
## Links
* A very comprehensive project to build an energy monitor can be found in the [ESP32 + ESPHome Open Source Energy Monitor project by Daniel BP](https://github.com/danpeig/ESP32EnergyMonitor).
* A nice (German) [video tutorial can be found at Eddie's Techlab](https://edistechlab.com/sct013-sensor-zum-wechselstrom-messen/).
* Have a look at the [complete documentation of the Open Energy Monitor project](https://docs.openenergymonitor.org/).
* There is also a German [example project](http://www.technik-fan.de/index.php/Open_Energy_Monitor_mit_dem_ESP32) (that currently cannot be reached over TLS, so be careful before clicking this link).
* MQTT and ESP32 is described in this article ["How to Connect ESP32 to MQTT Broker"](https://iotdesignpro.com/projects/how-to-connect-esp32-mqtt-broker).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

View file

@ -1,100 +0,0 @@
# Plant Monitor
## Existing project
We use our existing plant monitor for this project.
It can be found in this Git instance: [Plant sensor workshop](https://code.curious.bio/curious.bio/pflanzensensor-workshop)
## Tasmota
[Tasmota](https://tasmota.github.io/docs/) is an alternative Firmware for ESP8266. It's easy to use with it's graphical user interface.
You can flash Tasmota right from the browser using the [Tasmota Web Installer](https://tasmota.github.io/).
![Flash it](./docs/images/01-flash-1.png)
You have to connect your device through USB and select the right port. Exisisting firmware will be delete.
![Erase everything](./docs/images/02-flash-2.png)
After Tasmota has been flashed to your ESP, you can already set up your wifi.
![Set up Wifi](./docs/images/03-wifi.png)
After your device is connected to Wifi, you can switch over to the web UI of your device. Yes, your device now runs an embedded web server. There you can configure your device.
![Embedded web server](./docs/images/04-web-ui.png)
### Configure
Using this Web UI you can setup up your device: `Configure -> Configure Module`
Our Wemos D1 mini clone is a `generic device with 18 ports`. We have a DHT11 connected to D1 and an analogue measurement on A0.
![Basic configuration](./docs/images/05-configuration.png)
After configuring it this way, we can see you data in the web UI.
![Flash it](./docs/images/06-overview.png)
### MQTT
Tasmota's main protocol is MQTT. You can setup MQTT under `Configuration -> MQTT`.
![MQTT](./docs/images/07-setup-mqtt.png)
To send data more frequent (nice for debugging) you have to change the telemetry period to a lower level (than 300 s / 5 min). I'd went for 10 s.
![Telemetry interval](./docs/images/08-configure-telemetry-interval.png)
Then our device will send data like this:
```
{
"Time": "2023-02-26T17:19:55",
"ANALOG": {
"A0": 6
},
"DHT11": {
"Temperature": 19,
"Humidity": 44,
"DewPoint": 6.4
},
"TempUnit": "C"
}
```
You can subscribe to this MQTT event in Node-RED.
![Node-RED](./docs/images/08-node-red-overview.png)
There is a small converter function, so we only store the interesting values in InfluxDB.
```
return {
payload: {
temperature: Number(msg.payload.DHT11.Temperature),
humidity: Number(msg.payload.DHT11.Humidity)
}
};
```
We can query this data in InfluxDB.
![InfluxDB](./docs/images/09-influx.png)
This is our query.
```
from(bucket: "plant")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "msg")
|> filter(fn: (r) => r["_field"] == "temperature" or r["_field"] == "humidity")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
We can use this query to create a dashboard in Grafana.
![InfluxDB](./docs/images/10-grafana.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 KiB

View file

@ -1,127 +0,0 @@
# Shelly Plug (S)
Shelly Plugs S are quite cheap but relatively accurate to measure power consumptions less than 2.5 kW.
![Shelly Plug](https://shelly.hr/wp-content/uploads/2020/11/shelly_plug_s_1-1.jpg)
## Flash Tasmota
There's an OpenSource project to flash Tasmota on Shelly Plugs: [mg2x](https://github.com/arendst/mgos-to-tasmota)
Locate your Shellie's IP adress (in my case: 192.168.2.150) and update it "over the air" with the Tasmota firmware:
http://192.168.2.150/ota?url=http://ota.tasmota.com/tasmota/shelly/mg2tasmota-ShellyPlugS.zip
Your Shelly will return a JSON object that looks like that:
```
{
"status": "updating",
"has_update": false,
"new_version": "20230109-114426/v1.12.2-g32055ee",
"old_version": "20230109-114426/v1.12.2-g32055ee"
}
```
After a while your Shelly Plug S should be flashed with Tasmota firmware.
> Just be patient. This took longer than five minutes in my DSL connected network.
The Shelly Plus S will create create a new Wifi.
![Tasmota Wifi](./docs/images/wifi.png)
Join that Wifi and configure the device: http://192.164.4.1/
![Join Wifi](./docs/images/configure-wifi.png)
You can configure it as a BlitzWolf SHP product.
Then it offers you power measurement and a programmable toogle.
![BlitzWolf](./docs/images/blitzwolf.png)
It should be configurable just like our [plant monitor](../plant-monitor/README.md).
Just enable MQTT and enter a shorter telemetry period.
![MQTT](./docs/images/mqtt.png) ![Telemetry period](./docs/images/telemetry-period.png)
It will post MQTT messages unter a topic `tele/tasmota_891E97/SENSOR` like this one:
```
{
"Time": "2023-02-27T16:45:07",
"ENERGY": {
"TotalStartTime": "2023-02-27T16:33:06",
"Total": 0.004,
"Yesterday": 0,
"Today": 0.004,
"Period": 0,
"Power": 34,
"ApparentPower": 44,
"ReactivePower": 27,
"Factor": 0.79,
"Voltage": 253,
"Current": 0.172
}
}
```
We now can consume this messages in Node-RED, store them in InfluxDB and build a dashboard in Grafana.
### InfluxDB Bucket
I created a bucket called `shelly`in InfluxDB, so we can store the messages in this bucket.
### Node-RED
I create a usual flow in Node-RED. A MQTT node fetches the values.
![Node-RED](./docs/images/node-red.png)
The message is fed into a filter function to only store usefull information:
```
return {
payload: {
power: Number(msg.payload.ENERGY.Power),
voltage: Number(msg.payload.ENERGY.Voltage),
current: Number(msg.payload.ENERGY.Current)
}
};
````
The `payload` will be stored in InfluxDB in the bucket "shelly".
### InfluxDB Data Explorer
In Influx DB Data Explorer you can query the stored data.
![Data Explorer](./docs/images/data-explorer.png)
The query created by Data Explorer looks like that:
```
from(bucket: "shelly")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "msg")
|> filter(fn: (r) => r["_field"] == "power" or r["_field"] == "voltage" or r["_field"] == "current")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
### Grafana
Using this query you can crate a dashboard in Grafana.
![Grafana](./docs/images/grafana.png)
## Links
* [Pinout for the ESP8266 based Shelly Plug-S Smart Plug
](https://faulty.cloud/blog/shelly-plug-s-pinout)
* [Youtube video: Upgrade Shelly Switches | Easy NO Soldering Smart Garage Door Opener](https://www.youtube.com/watch?v=_oRr8FZyyQ0)
* [mg2x](https://github.com/arendst/mgos-to-tasmota)
* [Shelly Plug S Power Monitoring Plug Tasmota template](https://templates.blakadder.com/shelly_plug_S.html)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

View file

@ -676,5 +676,24 @@
"file": "/data/node_modules/node-red-contrib-influxdb/influxdb.js"
}
}
},
"node-red-contrib-watt2kwh": {
"name": "node-red-contrib-watt2kwh",
"version": "0.1.2",
"local": true,
"user": true,
"nodes": {
"simpletime": {
"name": "simpletime",
"types": [
"watt2kwh"
],
"enabled": true,
"local": true,
"user": false,
"module": "node-red-contrib-watt2kwh",
"file": "/data/node_modules/node-red-contrib-watt2kwh/watt2kwh.js"
}
}
}
}

View file

@ -654,5 +654,27 @@
"file": "/data/node_modules/node-red-dashboard/nodes/ui_spacer.js"
}
}
},
"node-red-contrib-influxdb": {
"name": "node-red-contrib-influxdb",
"version": "0.6.1",
"local": true,
"user": true,
"nodes": {
"influxdb": {
"name": "influxdb",
"types": [
"influxdb",
"influxdb out",
"influxdb batch",
"influxdb in"
],
"enabled": true,
"local": true,
"user": false,
"module": "node-red-contrib-influxdb",
"file": "/data/node_modules/node-red-contrib-influxdb/influxdb.js"
}
}
}
}

View file

@ -1,109 +0,0 @@
# About
> This folder will be mounted into the Node-RED runtime. So be careful.
# Node-RED
If you boot up our tech stack using `docker-compose` you already have a Node-RED instance running on [your local machine](http://localhost:1880/).
Node-RED is an open-source, low-code, visual programming tool based on the concept of flow-based development. The idea behind it is to make it very easy to connect APIs, hardware devices, and anything else accessible over some type of network connection.
## Core Concepts
Nodes are the important part of Node-Red. They are the building blocks when working with Node-Red. Nodes are triggered by either receiving a message object from a previous node or an external event like an MQTT event. The node processes the message or event and then passes it on to the next node.
A node can:
* Inject: Starts a flow by injecting a message or a payload.
* Change: Here you can do basic transformation or modification on the message object.
* Debug: Can be used to help developing flows by sending messages to the side bar.
* Switch: Here you can add logic (like sending the message to different nodes).
* Function: Add custom JavaScript for uses cases where simple nodes do not do the trick.
Flows are an organized sequence of nodes. Let's do the "first steps" by creating a simple flow.
## Plugins
> The plugin folder is pushed into this Git repository and is mounted in Docker. Maybe we should use an own Docker file, instead.
Node-RED uses plugins (e.g. for InfluxDB or own Dashboard capabilites).
You can access the plugins in the right burger menu.
![Plugins](./docs/images/node-red-plugins.png)
## First steps
For debuging I already added Node-RED's own dashboard (sure, we are going to use Grafana, later).
![Overview](./docs/images/1-overview.png)
The dashboard should be visible on the righmost menu item in Node-RED.
![Dashboard item](./docs/images/dashboard.png)
In Node-RED you can add a MQQT node to receive values from the power monitor. As we run in `docker-compose`you don't have to use the IP address of our Eclipse Mosquitto sever, but you can simply use `mosquitto` as the host nome.
![MQTT Node](./docs/images/2-mqtt-node.png)git a
To simply display the values in a gauge (or chart) you can hook it up to a gauge node.
![Gauge Node](./docs/images/3-gauge-node.png)
In the dasboard section you have to create a tab. Inside this tab you have to create a group.
![Dashboard Settings](./docs/images/4-dashboard-node.png)
The tricky part is putting the gauges in the group. This is done in the gauge's settings (not in the dashboard's settings).
![Gauge Node](./docs/images/3-gauge-node.png)
You can view the dashboard in an (also mobile) web browser.
![Mobile view](./docs/images/5-dashboard.png)
Have a look at the flow also in [this repository](./00-dashboard-example/dashboard.json).
## InfluxDB
Already added to this project is [node-red-contrib-influxdb](https://flows.nodered.org/node/node-red-contrib-influxdb). You can use it's nodes to write and query data from an InfluxDB time series database. These nodes support both InfluxDB 1.x and InfluxDb 2.0 databases. At the time of this writing we are using [version 2.6 of InfluxDB on port 8086](http://admin:adminadmin@localhost:8086).
In Node-RED we will be passing the power consumption number through MQTT.
![Overview](./docs/images/influx-flow.png)
By default this will be passed as a string, so we need to create a function to convert it into a Number before storing it in InfluxDB.
Add a function node to the page and put the following code into the node:
```JavaScript
msg.payload = Number(msg.payload)
return msg;
```
![Function](./docs/images/influx-function.png)
You can forward this message to InfluxDB.
![Influx Node](./docs/images/influx-node.png)
The `URL`of our InfluxDB is `http://influxdb:8086`. In InfluxDB you have to create a `token` to connect: [Load Data -> API Tokens](http://localhost:8086/orgs/721027680173bf2f/load-data/tokens).
![Influx Create Token](./docs/images/influx-create-token.png)
You can use this `token` to create a connection in Node-RED.
![Influx Connection](./docs/images/influx-connection.png)
Then the measurements should be visible in [Influx Data Explorer](http://localhost:8086/orgs/721027680173bf2f/data-explorer?bucket=test).
![Influx Data Explorer](./docs/images/influx-data-explorer.png)
As the data is now stored in Influx, [let's create a dashboard in Grafana](../dashboard/README.md).
# Links
* [IoT Made Easy with Node-RED and InfluxDB](https://www.influxdata.com/blog/iot-easy-node-red-influxdb/)
* A great tutorial can be found at [microcontrollerlab.com](https://microcontrollerslab.com/esp32-mqtt-publish-multiple-sensor-readings-node-red/)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB