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.