Wir wollen alle Daten der Sensoren und alle Aktionen über die Beckhoff Steuerung im Haus in einer Datenbank protokollieren. So ist es uns später möglich zu erkennen, welche Aktionen häufig ausgeführt werden und welche eher selten. Außerdem können wir Temperaturkurven für die einzelnen Räume erstellen. Von daher benötigen wir eine einfache Möglichkeit, Daten in eine Datenbank zu schicken. Hierfür setzen wir auf MariaDB, einen Ableger von MySQL.
Anlegen der MariaDB Datenbank
Beim Anlegen der Datenbank gehen wir den einfachen Weg und nutzen die MySQL Workbench. Mit dieser lassen sich ganz einfach Datenbanken und Tabellen anlegen. Da dies eine einmalige Aktion ist, lohnt es sich nicht, dafür etwas im SPS Programm vorzusehen. Dies bedeutet aber auch, dass wir nicht in der Software sicherstellen, dass es die Datenbank wirklich gibt. Für unser Häuschen ist das aber auch nicht notwendig.
Die Datenbank wird hier im Beispiel mit folgenden Daten angelegt:
Datenbankname: sensors User: myuser Passwort: mypassword
In dieser Datenbank legen wir eine Tabelle an, die folgende Spalten hat:
sensor : INT timestamp : TIMESTAMP value : REAL
Als Datenbank Befehl sieht das wir folgt aus:
CREATE SCHEMA `sensors` CREATE TABLE `sensors`.`sensing_values` ( `sensor` INT NOT NULL, `timestamp` TIMESTAMP NOT NULL, `value` REAL NOT NULL);
Jetzt muss sichergestellt werden, dass auch von Remote auf die Datenbank zugegriffen werden kann. Dazu muss die Konfiguration unter /etc/mysql/my.cnf
folgendes eingetragen werden:
bind-address = 0.0.0.0
Danach muss der MariaDB Service neu gestartet werden:
sudo /etc/init.d/mysql restart
Einrichtung der MariaDB Datenbank in der Beckhoff Steuerung
Für TwinCAT 3 gibt es von Beckhoff das “TF6420 TC3 Database Server” Supplement für Datenbankzugriffe. Damit wir in der SPS auf die Datenbank zugreifen können, muss die Datenbank erst einmal eingerichtet werden. Nach der Installation des Supplements gibt es ein Extra Tool unter C:\TwinCAT\Functions\TF6420-Database-Server\Win32\Configurator
, in dem man die Datenbanken verwalten kann. Hier werden die Daten eingetragen.
Hier wird unter Edit – NewDBConnection die neue Datenbank Verbindung angelegt.
Danach muss die Datenbank zum Datenbank-Pool hinzugefügt werden. Dazu einen Rechtsklick auf den Namen ServerDB in der linken Box und “Add to DB Configuration Pool” auswählen. Die Datenbank taucht dann unten rechts in der Box auf.
Als nächstes muss die Datenbank in das eigentliche Projekt eingebunden werden. Dazu wählen wir als erstes die Toolbar “TwinCAT Database Server” (unter View-Toolbars) aus. Jetzt kann die Datenbank eingebunden werden. Die Datenbank taucht im Datenbank Pool auf, die man mit folgendem Icon aufrufen kann:
Hier findet man dann die Datenbank.
Senden von Daten an die Datenbank
Für das Senden von Daten an die Datenbank verwenden wir den SPS Baustein “FB_SQLDatabase” und “FB_SQLCommand”. Das Ganze wird in einer Klasse gekapselt, so dass von außen nur neue Daten hinzugefügt werden müssen.
VAR nWriteState : DBWriterState; _buffers: ARRAY[0..1] OF ARRAY[0..lengthOfBuffer-1] OF DBSensorData; _actBufferNumber : INT := 0; _actPos: INT := 0; fbSQLDatabase: FB_SQLDatabase(sNetID:=ip, tTimeout:=T#10S); fbSQLCommand: FB_SQLCommand(sNetID:=ip, tTimeout:=T#10S); nDBID: UDINT := 1; END_VAR VAR CONSTANT ip : T_AmsNetID := ''; lengthOfBuffer : INT := 20; END_VAR
Dabei wird bei jedem Aufruf der Klasse die Update Funktion aufgerufen:
Update();
So kann im Hauptprogramm einfach das Update der DB in jedem Zyklus gestartet werden. Die Update Funktion ruft einfach nur die Funktion “WriteToDatabase” Funktion auf.
METHOD WriteToDatabase : BOOL VAR_INPUT nBufferID : INT := -1; END_VAR VAR_STAT actBuffer : POINTER TO ARRAY[0..lengthOfBuffer-1] OF DBSensorData; insertdata : STRING[65 + 35 * lengthOfBuffer]; insertLength : UDINT := 0; END_VAR IF nBufferID >= 0 THEN actBuffer := ADR(_buffers[nBufferId]); END_IF; CASE nWriteState OF DBWriterState.waiting:(*Idle*) IF nBufferID >= 0 THEN nWriteState := DBWriterState.openDB; END_IF DBWriterState.openDB: // Connect to database IF NOT fbSQLDatabase.Connect(hDBID:= nDBID) THEN IF LogError(fbSQLDatabase.ipTcResultEvent) THEN nWriteState := DBWriterState.closeDBStep1; END_IF ELSE nWriteState := DBWriterState.openDBWait; END_IF DBWriterState.openDBWait: fbSQLDatabase(); IF NOT fbSQLDatabase.bBusy THEN IF LogError(fbSQLDatabase.ipTcResultEvent) THEN nWriteState := DBWriterState.closeDBStep1; ELSE fbSQLDatabase.CreateCmd(ADR(fbSQLCommand)); nWriteState := DBWriterState.prepareWriteDB; END_IF END_IF DBWriterState.prepareWriteDB: BuildInsertCommand(buffer := actBuffer, insertCommand => insertdata, length => insertLength ); nWriteState := DBWriterState.writeDB; DBWriterState.writeDB: IF NOT fbSQLCommand.Execute(ADR(insertdata), insertlength) THEN IF LogError(fbSQLCommand.ipTcResultEvent) THEN nWriteState := DBWriterState.closeDBStep1; END_IF ELSE nWriteState := DBWriterState.writeDBWait; END_IF DBWriterState.writeDBWait: fbSQLCommand(); IF NOT fbSQLCommand.bBusy THEN IF LogError(fbSQLCommand.ipTcResultEvent) THEN nWriteState := DBWriterState.writeDB; END_IF nWriteState := DBWriterState.closeDBStep1; END_IF DBWriterState.closeDBStep1: IF NOT fbSQLDatabase.Disconnect() THEN IF LogError(fbSQLDatabase.ipTcResultEvent) THEN nWriteState := DBWriterState.openDB; END_IF ELSE nWriteState := DBWriterState.closeDBStep2; END_IF DBWriterState.closeDBStep2: fbSQLDatabase(); IF NOT fbSQLDatabase.bBusy THEN nWriteState := DBWriterState.waiting; END_IF END_CASE
Einbinden der Tabellen in Django
Jetzt haben wir die Daten in der Datenbank. Überprüfen kann man sie direkt per SQL:
SELECT * FROM sensing_values;
So helfen sie uns gerade aber nicht sehr viel. Wir wollen die Daten in unserer Visualisierung auch darstellen können. Dazu brauchen wir eine einfacher Möglichkeit auf unsere Tabelle zuzugreifen. Hier bietet Django mit seinen Models eine einfache Möglichkeit. Wir tragen hier die Datenbank ein und können sie dann über die normalen Models Funktionen verwenden.
Damit wir auf unsere Datenbank zugreifen können, müssen wir sie erstmal in den Settings als Datenbank eintragen. Hier nutzen wir aus, dass MariaDB und MySQL sich sehr ähneln.
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'USER': 'myuser', 'PASSWORD': 'mypassword', 'NAME': 'sensors', 'sql_mode': 'STRICT_ALL_TABLES', 'OPTIONS': { 'charset': 'latin1', 'use_unicode': 'True', }, }, }
In der entsprechenden models.py wird jetzt die Datenbank eingebunden:
class SensingValue(models.Model): sensor = models.IntegerField(primary_key=True, editable=False) timestamp = models.DateTimeField(primary_key=True, editable=False) value = models.FloatField(editable=False) class Meta: db_table = 'sensing_values' managed = False
Jetzt kann direkt auf die Daten zugegriffen werden, um sie zum Beispiel in der Oberfläche anzuzeigen. Hier werden alle Daten des Sensors mit der ID id ausgelesen, die zwischen since und now liegen.
values = SensingValue.objects.filter(sensor=id, timestamp__lte = now, timestamp__gte = since)
Mit den Standard Django Funktionen lassen sich nun weitere Funktionen und passende Datenbanken zur Verwaltung hinzufügen.
Hi,
i tried several time to startup MySql connection through TF6420 but every time i check the connection i retrive this message
“Configuration check failed SQLState_HY000 General error”. Any suggestions?
I tried with firebird databese and works, but i would like to use MySql.
Thx
TF6420 version 3.2.32.2
MySql version 8.0.17
TwinCAT version 3.1.4022.22
Hi Michele,
sorry, I never had this message. Can you connect from the PC to the MySQL database using another client? Perhaps your firewall is the error source.