'Inteligenty' dom ze sterownikiem PLC

 Language:
Szukanie zaawansowane  

Aktualności:

Powrót do strony głównej: www.edom-plc.pl

Autor Wątek: SQL i analiza zużycia energii  (Przeczytany 17480 razy)

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
SQL i analiza zużycia energii
« dnia: Stycznia 07, 2013, 05:44:09 pm »

Witam

Chciałbym zrobić podobnie jak u Pana z pomiarem temperatury i wysyłaniem do bazy SQL. W moim przypadku jest podobnie, serwer nie działa w nocy.
Czyli wysyłannie co jakiś czas, a w przypadku braku połączenia przechowywanie w pamięci... Zakladam że będę wysyłał ilość impulsów.
Dopiero zaczynam poruszać się w ST i nie wszystko jest dla mnie zrozumiałe..
Czy  CURRENT_TIME to bierzący czas?
Co oznacza SensorReader?

Pozdrawiam


Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
SQL i analiza zużycia energii
« Odpowiedź #1 dnia: Stycznia 07, 2013, 08:59:09 pm »

Witam,

CURRENT_TIME to zmienna globalna typu DATE_AND_TIME, która jest aktualizowana co 1 sek. w odrębnym procesie (o procesach - http://www.edom-plc.pl/index.php?option=com_content&view=article&id=93)

VAR_GLOBAL
   CURRENT_TIME            :DATE_AND_TIME;
END_VAR

Każdy program i proces, który potrzebuje do działania aktualny czas sięga do tej zmiennej.

SensorReader to właśnie oddzielny proces, który odczytuje wartości wejść analogowych i koryguje je o ustalony empirycznie offset.

Co do wysyłania do bazy proponowałbym wysyłać dane zakumulowane, np. zużycia w kWh zarejestrowane przez dany miernik w okresie 10 min.  Wysyłana więc byłaby tabela: czas, kWh z miernika 1, kWh z miernika 2 itd.. 

Na początek mogę też zaproponować zapisywanie takich danych w wewnętrznej pamięci sterownika w pliku csv do późniejszej analizy w excelu.

Pozdrawiam!
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #2 dnia: Stycznia 08, 2013, 09:05:17 am »

Witam


A co robi Command :STRING(150);?

Pozdrawiam
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #3 dnia: Stycznia 08, 2013, 12:14:50 pm »

definiuje zmienną typu STRING o długości 150 znaków.
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #4 dnia: Stycznia 09, 2013, 08:31:02 pm »

Witam

Nie dokońc też rozumiem działanie tego:

VAR
SQLWrite_Interval :TP:=(IN:=TRUE, PT:=T#20m); (* odmierza czas między zapisami (20 minut) *)
SQLWrite_StartSignal :F_TRIG; (* który przez 1 cykl programu sygnalizuje początek sygnału zapisywania *)


Program
SQLWrite_StartSignal(CLK:=NOT SQLWrite_Interval.Q);
SQLWrite_Interval(IN:=SQLWrite_StartSignal.Q);

Rozumiem że służy do odmierzania czasu i sygnalizacji.
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #5 dnia: Stycznia 09, 2013, 08:49:22 pm »

Tak jest,

Przez 20 minut SQLWrite_Interval.Q jest TRUE.  W pierwszym cyklu, gdy zmieni się na False, SQLWrite_StartSignal zapoda na zmiennej wyjściowej Q wartość TRUE.  Ta wartość zostanie wykorzystana przez program do rozpoczęcia przesyłania, ale też uruchomi od nowa zegar SQLWrite_Interval.

...co akurat sprawia, że zauważyłem błąd w przykładzie, powinno być:

VAR
SQLWrite_Interval :TP:=(IN:=TRUE, PT:=T#20m); (* odmierza czas między zapisami (20 minut) *)
SQLWrite_StartSignal :R_TRIG; (* który przez 1 cykl programu sygnalizuje początek sygnału zapisywania *)
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #6 dnia: Stycznia 10, 2013, 08:36:25 am »

Witam

No właśnie nie chciało działać...teraz jest OK.
Jest jeszcze jedna sprawa w tym miejscu:

VAR_GLOBAL CONSTANT

  gcMySql_iSqlUpperBound :INT:=59;
  gcMySql_iSqlLength :INT:=150;
END_VAR
przy  VAR_GLOBAL CONSTANT wskazuje błąd „Oczekiwano VAR, VAR_INPUT, VAR_OUTPUT lub VAR_IN_OUT”


 

Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #7 dnia: Stycznia 10, 2013, 02:04:21 pm »

Witam,

to powinno trafić w Resources->Global_Variables,

Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #8 dnia: Stycznia 10, 2013, 08:09:30 pm »

Witam

Prosze spojrzeć na moj program do wysyłania ilości impulsów z licznika energii na serwer, wydaje mi się że nie działa prawidłowo...

PROGRAM PLC_PRG
VAR
   oMySql : MySql_Context;  (* Structure for keeping login and status informations ,  to kontekst logowania, komunikacji i wylogowywania*)

   SQLWrite_Interval :TP:=(IN:=TRUE, PT:=T#5m); (* odmierza czas między zapisami (1 minuta) *)
   SQLWrite_StartSignal :R_TRIG; (* który przez 1 cykl programu sygnalizuje początek sygnału zapisywania *)

   Command :STRING(150); (* wykorzystywana do konstruowania komendy SQL *)
   Energy_Command :ARRAY [0..59] OF STRING(150); (* *)
    ManualLogin, ManualLogout, ManualExecute, ManualStorageClean :BOOL; (* zmienne do uruchamiania poszczególnych etapów za pomocą wizualizacji - na potrzeby testów *)
    Energy_Login :BOOL; (* przechowuje sygnał rozpoczęcia logowania *)
    Energy_LoginEnds :R_TRIG; (* trigger do sygnalizowania udanego zalogowania*)
    Energy_Execute :BOOL; (* przechowuje sygnał rozpoczęcia wysyłania polecenia SQL *)
    Energy_SQLQuery : MySql_Execute; (*  przechowuje sygnał rozpoczęcia wysyłania polecenia SQL *)
    Energy_ExecuteEnds :R_TRIG; (* trigger do sygnalizowania końca komunikacji z bazą SQL *)
     i :BYTE; (* zmienna techniczna *)

   Energy_CommandCounter :BYTE:=0;  (* przechowuje informacje i ilości komend przechowywanych w TemperatureCommand *)

     Energy_Logout :BOOL; (*przechowuje sygnał rozpoczęcia wylogowywania*)
     Energy_SQLLogout:MySql_Logout; (*blok funkcyjny odpowiedzialny za wylogowanie z bazy*)

(*Blok funkcyjny, aby połączyć się z  MySQL-Server*)

   oMySqlLogin : MySql_Login;
   xConnect                : BOOL;
   diErrorLogin             : DINT;
   sStatusLogin             : STRING(500);
   xConnected             : BOOL;       (* TRUE: połączenie z bazą danych, gdy zostanie ustalone *)
   sHost                   : STRING :='xxxxxx';
   uiPort                  : UINT :=3306;
   sUser                   : STRING :='user';
   sPWD                   : STRING :='xxxxxx';
   sDB                   : STRING :='WagoDB';
   sTable                : STRING :='data';

(* Blok funkcyjny do przetwarzania instrukcji SQL *)

   oMySqlExec1 : MySql_Execute;
   xExec1 : BOOL;
   diErrorExec1 : DINT;
   sStatusExec1 : STRING(500);

(* Blok funkcyjny do odłączenia serwera MySQL *)

   oMySqlLogout : MySql_Logout;
   xDisconnect : BOOL;
   diErrorLogout : DINT;
   sStatusLogout : STRING(500);

   Licznik_Log: CTU ; (*Licznik logowań *)
   s_Table: STRING;

END_VAR
VAR_INPUT
   CU: BOOL;         (* Licznik w górę *)
   RESET: BOOL;      (* Reset licznika do 0 *)
   PV: WORD;         (* Limit licznika *)
   CURRENT_TIME: DT;
   Energy_1: WORD;    (*Liczba impulsów licznika energii*)
END_VAR
VAR_OUTPUT
   Q: BOOL;      (* Licznik osiągnął limit *)
   CV: WORD;      (* Aktualna wartość licznika *)
END_VAR
VAR
   M: BOOL;       (* Zmienna dla CU wykrywanie krawędzi *)
END_VAR


i Program:

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 Data (Timestamp, Energy_1) 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,WORD_TO_STRING(Energy_1));
Command:=CONCAT(Command,',');

Energy_Command[Energy_CommandCounter]:=Command;
Energy_CommandCounter:=Energy_CommandCounter+1;


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

(* Rozpocznij komunikację z Bazą SQL *)
Energy_Login:=SQLWrite_StartSignal.Q OR ManualLogin;
oMySqlLogin(sHost:=sHost, sUsername:=sUser, sPassword:=sPWD, sDatabase:=sDB,oMySql:=oMySql, xStart:=Energy_Login);
Energy_LoginEnds(CLK:=oMySqlLogin .xConnected);
Energy_Execute:=Energy_LoginEnds.Q OR ManualExecute;
Energy_SQLQuery(xStart:=Energy_Execute, oMySql:=oMySql, asSqlCommand:=Energy_Command);
Energy_ExecuteEnds(CLK:=(Energy_SQLQuery.wState=0));


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

(* Wyloguj z Bazy SQL *)
Energy_Logout:=(Energy_ExecuteEnds.Q OR ManualLogout);
Energy_SQLLogout(xStart:= Energy_Logout, oMySql:=oMySql);

(*Licznik energii*)

(* Licznik logowań *)
Licznik_Log(CU:= Energy_Login ,RESET:=RESET , PV:= PV);
 Q := Licznik_Log.Q ;
 PV := Licznik_Log.CV;
END_IF

Jak coś mogę wysłać też na maila....

pozdrawiam
i z góry dzięuję za pomoc
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #9 dnia: Stycznia 13, 2013, 01:03:07 pm »

Witam

Widziałem na na stronce wykresy ze zużycia energii...czy one sięgają do sterownika, czy do bazy SQL?

Mam pytanie jeszcze do tego wysyłania do bazy,  dane są zbierane do pamieci sterownika i potem wysyłane w paczce do bazy? Jak potem z tymi paczkami w bazie?
Jeżeli chodzi o sam zapis w tablicy, w ktorym miejscu jest informacja o pobieraniu danych (przedział czasu ...) np temperatury, energii?

Pozdrawiam
Paweł
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #10 dnia: Stycznia 13, 2013, 01:53:11 pm »

Witam,

na początek - kod wydaje się ok.  Nikt jednak nie uniknie debugowania na własnym sterowniku, więc proponuję po prostu próbować do skutku.

Wykresy historycznego zużycia energii sięgają do bazy/pliku csv.  W sterowniku nie przechowuję takiej ilości danych.

Dane są 'zbierane w pamięci' jako lista komend SQL.  W momencie wysłania, wszystkie nagromadzone polecenia wykonują się jedno za drugim więc dla bazy jest to przejrzyste.

Inaczej mówiąc, tablica wysyłana do serwera SQL wypełniana jest liniami:

INSERT INTO Data (Timestamp, Energy_1) VALUES (Time, Energy)

Po skutecznym wysłaniu danych do bazy, tablica jest czyszczona:

IF (Energy_ExecuteEnds.Q AND (Energy_SQLQuery.diError=16#00000000)) OR ManualStorageClean THEN
  Energy_CommandCounter:=0;
  FOR i:=0 TO 59 BY 1 DO
    Energy_Command:='';
  END_FOR;
END_IF;

Wypełnianie tablicy dokonywane jest tu:

IF (SQLWrite_StartSignal.Q OR ManualLogin) THEN
Command:='INSERT INTO Data (Timestamp, Energy_1) 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,WORD_TO_STRING(Energy_1));
Command:=CONCAT(Command,',');

Energy_Command[Energy_CommandCounter]:=Command;

przez odpowiednie przeformatowanie danych przechowywanych w CURRENT_TIME i Energy_1.

ostatecznie przygotowana komenda przypisana do zmiennej Command, wpisywana jest na kolejnym miejscu w tablicy Energy_Command.

Pozdrawiam,
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #11 dnia: Stycznia 13, 2013, 02:45:10 pm »

Witam

Występuje zmienna Timestamp i Current_Time...Ta druga to czas odpowiednio obrabiany przez MID i RIGHT. A Timestamp?

Może bład jest w samej bazie...
Zrobiłem 3 kolumny:

Timetamp        typ Timestamp
Current_Time   typ datetime
Energy_1         typ INT

Pozdrawiam
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #12 dnia: Stycznia 13, 2013, 03:01:39 pm »

Timestamp to nie zmienna a nazwa kolumny w bazie

INSERT INTO Data (Timestamp, Energy_1) VALUES (jakiś czas, jakieś zużycie)

Skoro w bazie masz Timetamp (brakuje s?) to nie potrzebna jest Current_Time, albo na odwrót.  Generalnie interesuje nas czas i zużycie podane z PLC, a nie czas samego zapisu w SQ.

Proponowałbym więc bazę o strukturze:
Timestamp, typ datetime
Energy_1 typ INT

obie bez wartości domyślnych
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #13 dnia: Stycznia 13, 2013, 05:55:05 pm »

Dziękuję za pomoc, nadal walczę z tematem....

Jak wyznaczany jest moment co ile ma być zapis np temperatury w pamieci sterownika, bo wysyłanie jest np co 20min?

Wyświetla mi np taki komunikat:

'MYSQL-ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near $'$' at line 1'

Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #14 dnia: Stycznia 14, 2013, 10:13:31 am »

Witam,

o częstotliwości zapisu decyduje

SQLWrite_Interval :TP:=(IN:=TRUE, PT:=T#5m);

Tu jest co 5 min.

Jeśli jest błąd składni MySQL, trzeba przeanalizować, co pojawia sie w zmiennej Command po tym, jak wykonane zostanie:

Command:='INSERT INTO Data (Timestamp, Energy_1) VALUES ("';
(...)
Command:=CONCAT(Command,WORD_TO_STRING(Energy_1));
Command:=CONCAT(Command,',');

Jest to już kwestia prób i błędów, by zapis wyglądał tak:

INSERT INTO NazwaTabeli (NazwaKolumny1, NazwaKolumny2) VALUES ("WartośćDoWpisaniaWKolumne1", "WartośćDoWpisaniaWKolumne2")

Pozdrawiam,
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #15 dnia: Stycznia 14, 2013, 10:29:44 am »

Witam

czyli co 5m jest zapis np. temperatury do tablicy, a wysyłanie do bazy SQL?

Co do skladni:

sTemp:='INSERT INTO Data (Timestamp,Energy_1) VALUES  ("';
sTemp:=CONCAT(sTemp,MID(DT_TO_STRING(Current_Time),10,4));
sTemp:=CONCAT(sTemp,' ');
sTemp:=CONCAT(sTemp,RIGHT(DT_TO_STRING(Current_Time),8));
sTemp:=CONCAT(sTemp,'",');
sTemp :=CONCAT(sTemp, WORD_TO_STRING(i_Energy_1));
sTemp :=CONCAT(sTemp, ', ' );
SQLStatement := sTemp;

to po uruchomieniu wygląda to tak (fragment):

'INSERT INTO Data (Timestamp,Energy_1) VALUES  ("1970-01-01 00:00:00",0, '

Wydaje mi się że nie jest to prawidłowe...



Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #16 dnia: Stycznia 14, 2013, 11:26:04 am »

Wprowadziłem poprawkę w składni

sTemp:='INSERT INTO Data (Timestamp,Energy_1) VALUES  ("';
sTemp:=CONCAT(sTemp,MID(DT_TO_STRING(Current_Time),10,4));
sTemp:=CONCAT(sTemp,' ');
sTemp:=CONCAT(sTemp,RIGHT(DT_TO_STRING(Current_Time),8));
sTemp:=CONCAT(sTemp,'","');
sTemp :=CONCAT(sTemp, WORD_TO_STRING(Energy_1));
sTemp :=CONCAT(sTemp ,'")');
SQLStatement := sTemp;

i jest:

'INSERT INTO Data (Timestamp,Energy_1) VALUES  ("1970-01-01 00:00:00","0")'

póżniej wgram do sterownika i zobaczę.
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #17 dnia: Stycznia 14, 2013, 11:59:58 am »

Ten sam interwał dotyczy wysyłania do bazy, co zapisywania w tablicy.  Jeśli jednak wysłanie nie bedzie skuteczne, tablica nie będzie wyczyszczona.  Jeśli komunikacja z serwerem SQL się powiedzie, wszystko rozpoczyna się od początku.
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #18 dnia: Stycznia 14, 2013, 12:15:07 pm »

Wysyłka do bazy jest np. co 20min, ale sam zapis do tablicy np danych o temperaturze?
A w przypadku kiedy nie możemy się łączyc z bazą np. w nocy?
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #19 dnia: Stycznia 14, 2013, 01:32:27 pm »

Co 20 minut wykonywane są zadania:
1. Wpisz do tablicy interesujące dane (np zużycie energii lub bieżącą temperaturę), zwiększ index tablicy o 1,
2. Wyślij zawartość tablicy na serwer,
3. Jeśli wysyłanie jest pomyślne, index=0 i wyczyść tablicę.

Czyli jeśli nie ma połączenia, tablica nie jest czyszczona i za 20 min kolejny wpis pojawi się w kolejnej pozycji = dane są magazynowane w tablicy.
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #20 dnia: Lutego 13, 2013, 09:41:02 am »

Witam

Napotkałem teraz taki problem:
- jeżeli serwer działa to dane są wysyłane do bazy SQL i jest ok
- jeżeli serwer nie działa to dane są gromadzone w tablicy i są na podglądzie tablicy (status mam  "TIMEOUT On: Try to connect 192.168...." zawartości tablicy )

ale gdy serwer juz dziala i sterownik chce wysłać to nie wysyła już i wszystko przestaje funkcjonować.

Pozdrawiam
Zapisane

admin

  • Administrator
  • Sr. Member
  • *****
  • Wiadomości: 313
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #21 dnia: Lutego 13, 2013, 12:43:34 pm »

Cześć,

bez kodu źródłowego się nie obędzie.  Ale tak na wyczucie - jest jakiś błąd w składni sql, np brak średnika za nawiasem kończącym daną linię:

...
sTemp :=CONCAT(sTemp, WORD_TO_STRING(Energy_1));
sTemp :=CONCAT(sTemp,');');
SQLStatement := sTemp;

Pozdraiwam,
Zapisane

Paweł Piotrowski

  • Newbie
  • *
  • Wiadomości: 23
    • Zobacz profil
Odp: SQL i analiza zużycia energii
« Odpowiedź #22 dnia: Lutego 14, 2013, 07:55:39 am »

cześć

wygląda to tak:

IF (StartSignal.Q) THEN
Command:='INSERT INTO Data (Timestamp,Energy_1) 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(Energy_1));
Command:=CONCAT(Command,'");');

możliwe że to to, dodałem i zobaczę póżniej czy zadziała

pozdrawiam
Zapisane