Używamy plików cookies (tzw. ciasteczka) by spersonalizować treść i ogłoszenia oraz by analizować ruch na stronie.  W sposób automatyczny dzielimy się informacjami o Twoim użyciu tego portalu z dostawcami ogłoszeń, którzy mogą połączyć te informacje z informacjami, które im udzieliłaś/łeś lub, które sami zebrali. Korzystanie z witryny bez zmiany ustawień dotyczących cookies oznacza, że będą one zamieszczane w Państwa urządzeniu końcowym.  Możecie Państwo dokonać w każdym czasie zmiany ustawień dotyczących cookies zmieniając opcje przeglądarki.

Wysyłanie danych do bazy SQL

Wago 750-841 jest sterownikiem sieciowym - w jego nazwie pojawia się słowo 'Ethernet'.  Dzięki podłączeniu do sieci obsługuje wiele dodatkowych potężnych funkcji.  W niniejszym artykule opiszę wysyłanie danych ze sterownika do bazy SQL.

Wszystkim zainteresowanym polecam film, który szczegółowo opisuje wszystkie kroki. Zapraszam również do lektury opisu biblioteki WagoLibMySql i noty aplikacyjnej.

Zacząć trzeba oczywiście od przygotowania samej bazy.  Na moim sieciowym serwerze stworzyłem bazę WagoDB i przypisałem do niej użytkownika wago. W bazie danych stworzyłem tabelę 'Temperatures' o 5 kolumnach: 'Timestamp', 'Temp1'...'Temp4'.

Ponadto w 'Menadżerze zdalnego połączenia MySQL' ustaliłem dostęp z zewnątrz dla wszystkich hostów.  O szczegółach tego procesu rozpisywać się nie będę - polecam film, notki aplikacyjne i googla.

Chciałem, aby co 20 minut mój sterownik wysyłał do bazy SQL dane o temperaturze z 4 czujników. Ponadto, w przypadku problemów z połączeniem (mój router jest wyłączony w nocy) dane o temperaturach powinny być przechowywane w pamięci i przekazywane do bazy przy uzyskaniu pierwszego pomyślnego połączenia. Aby to zrobić konieczne były następujące kroki po stronie PLC:

  1. Dodanie bibliotek WagoLibMySQL_03.lib oraz WagoLibSHA1.lib (do ściągnięcia z www.wago.pl, Oprogramowanie do pobrania, AUTOMATION, Libraries)
  2. Dodanie nowego Programu (prawy przycisk na drzewo POUs, Add Object) o nazwie SQL_DataStorage w języku ST.
  3. Dodanie nowego zadania w Task Configuration.  W moim programie nazwałem je SQLConnector, ustawiłem cykl wykonywania co 50ms (T#50ms) i dodałem Program Call: SQL_DataStorage().  W efekcie SQL_DataStorage wykonywane jest co pół sekundy.
  4. Dodanie zmiennej globalnej, która pozwoli rozszerzyć tablicę przechowującą komendy SQL: Resources, Global Variables:
VAR_GLOBAL CONSTANT
	gcMySql_iSqlUpperBound :INT:=59;
	gcMySql_iSqlLength :INT:=150;
END_VAR

W programie SQL_DataStorage() w części definicjy zmiennych:

VAR
	SQLWrite_Interval :TP:=(IN:=TRUE, PT:=T#20m);
	SQLWrite_StartSignal :R_TRIG;
	
	Command :STRING(150);
	TemperatureCommand :ARRAY [0..59] OF STRING(150);
	
	ManualLogin, ManualLogout, ManualExecute, ManualStorageClean :BOOL;
	
	TemperatureLogin :BOOL;
	TemperatureSQLLogin :MySql_Login;

	Host: STRING:='xxxxxxxxx';
	User: STRING:='xxxxxxxxx';
	Password: STRING:='xxxxxxxxxxx';
	Database:STRING:='xxxxxxxxxxxx';

	TemperatureConnection :MySql_Context;

	TemperatureLoginEnds :R_TRIG;
	TemperatureExecute :BOOL;
	TemperatureSQLQuery : MySql_Execute;

	TemperatureExecuteEnds :R_TRIG;

	TemperatureCommandCounter :BYTE:=0; 
	i :BYTE;
	TemperatureLogout :BOOL;
	TemperatureSQLLogout:MySql_Logout;
END_VAR

Gdzie:

  • SQLWrite_Interval - odmierza czas między zapisami (20 minut),
  • SQLWrite_StartSignal - który przez 1 cykl programu sygnalizuje początek sygnału zapisywania
  • Command - wykorzystywana do konstruowania komendy SQL,
  • TemperatureCommand - jest tablicą, która przechowuje komendy SQL (jej rozmiar odpowiada parameterom zmiennych globalnych),
  • ManualLogin, ManualLogout, ManualExecute, ManualStorageClean - zmienne do uruchamiania poszczególnych etapów za pomocą wizualizacji - na potrzeby testów.
  • TemperatureLogin - przechowuje sygnał rozpoczęcia logowania
  • TemperatureSQLLogin - to blok funkcyjny odpowiedzialny za logowanie do bazy
  • Host, User, Password, Database - zmienne przechowujące dane do logowania, zdefiniowanie ich w ten sposób umożliwia modyfikowanie ich przy uruchomionym programie poprzez wizualizację,
  • TemperatureConnection - to kontekst logowania, komunikacji i wylogowywania
  • TemperatureLoginEnds -  trigger do sygnalizowania udanego zalogowania
  • TemperatureExecute - przechowuje sygnał rozpoczęcia wysyłania polecenia SQL
  • TemperatureSQLQuery - blok funkcyjny odpowiedzialny za komunikację z bazą SQL
  • TemperatureExecuteEnds - trigger do sygnalizowania końca komunikacji z bazą SQL
  • TemperatureCommandCounter - przechowuje informacje i ilości komend przechowywanych w TemperatureCommand
  • i - zmienna techniczna
  • TemperatureLogout - przechowuje sygnał rozpoczęcia wylogowywania
  • TemperatureSQLLogout - blok funkcyjny odpowiedzialny za wylogowanie z bazy

W części programowej:

SQLWrite_StartSignal(CLK:=NOT SQLWrite_Interval.Q);

SQLWrite_Interval(IN:=SQLWrite_StartSignal.Q);

(* Przygotuj komendę SQL *)
IF (SQLWrite_StartSignal.Q OR ManualLogin) THEN
	Command:='INSERT INTO Temperatures (Timestamp, Temp1, Temp2, Temp3, Temp4) VALUES ("';
	Command:=CONCAT(Command,MID(DT_TO_STRING(CURRENT_TIME),10,4));
	Command:=CONCAT(Command,' ');
	Command:=CONCAT(Command,RIGHT(DT_TO_STRING(CURRENT_TIME),8));
	Command:=CONCAT(Command,'",');
	Command:=CONCAT(Command,REAL_TO_STRING(SensorReader.TEMPERATURE_1));
	Command:=CONCAT(Command,',');
	Command:=CONCAT(Command,REAL_TO_STRING(SensorReader.TEMPERATURE_5));
	Command:=CONCAT(Command,',');
	Command:=CONCAT(Command,REAL_TO_STRING(SensorReader.TEMPERATURE_6));
	Command:=CONCAT(Command,',');
	Command:=CONCAT(Command,REAL_TO_STRING(SensorReader.TEMPERATURE_8));
	Command:=CONCAT(Command,');');
	TemperatureCommand[TemperatureCommandCounter]:=Command;
	TemperatureCommandCounter:=TemperatureCommandCounter+1;

(* Jeśli tablica jest pełna wyzeruj licznik, zacznij zapisy od początku *)
	IF TemperatureCommandCounter=60 THEN
		TemperatureCommandCounter:=0;
	END_IF;
END_IF;

(* Rozpocznij komunikację z Bazą SQL *)
TemperatureLogin:=SQLWrite_StartSignal.Q OR ManualLogin;
TemperatureSQLLogin(sHost:=Host, sUsername:=User, sPassword:=Password, sDatabase:=Database,oMySql:=TemperatureConnection, xStart:=TemperatureLogin);
TemperatureLoginEnds(CLK:=TemperatureSQLLogin.xConnected);

TemperatureExecute:=TemperatureLoginEnds.Q OR ManualExecute;
TemperatureSQLQuery(xStart:=TemperatureExecute, oMySql:=TemperatureConnection, asSqlCommand:=TemperatureCommand);
TemperatureExecuteEnds(CLK:=(TemperatureSQLQuery.wState=0));

(* Przy pomyślnym zapisie do Bazy SQL, wyczyść tablicę TemperatureCommand *)
IF (TemperatureExecuteEnds.Q AND (TemperatureSQLQuery.diError=16#00000000)) OR ManualStorageClean THEN
	TemperatureCommandCounter:=0;
	FOR i:=0 TO 59 BY 1 DO
		TemperatureCommand[i]:='';
	END_FOR;
END_IF;

(* Wyloguj z Bazy SQL *)
TemperatureLogout:=(TemperatureExecuteEnds.Q OR ManualLogout);
TemperatureSQLLogout(xStart:= TemperatureLogout, oMySql:=TemperatureConnection);

Aby obserwować przebieg i sprawdzać postępy komunikacji proponuję zbudować prostą wizualizację, w której umieścić trzeba przyciski zmieniające wartości zmiennych ManualLogin, ManualLogout, ManualExecute, ManualStorageClean i pola tekstowe wyświetlające zmienne wyjściowe sStatus wszystkich 3 bloków funkcyjnych: TemperatureSQLLogin, TemperatureSQLQuery, TemperatureSQLLogout.

Po co to wszystko?  Ano choćby po to, by przeanalizować temperatury w zadanym okresie czasowym.  Przykładowy, zrobiony na szybko wykres wygląda tak: (to oczywiscie wizualizacja w html, w oparciu o Highcharts Tools...)

Temperatury

Opis, jak zbudować wykresy dostępne przez przeglądarkę znajduje się w artykule Wykresy Danych - Highcharts