-> Hier kostenlos registrieren
Hallo zusammen,
erst einmal möchte ich Danke sagen an @Blockmove, der mit einem kleinen Denkanstoß dafür sorgte, dass ich mir mal schnell Gedanken machte über meine Solaranlage. Man muss dazu sagen, dass dieses Projekt erst ging, nachdem ich meinen Solar-log 500 über die Firmware 2.8.1 Build 49 gezogen hatte, aktuell Firmware 3.6.0 Build 99. Dadurch hatte ich Zugriff auf Modbus TCP. Ich habe die Bausteine nur mit der S7-1500 gemacht, bei anderen Steuerungen müssen eben Anpassungen gemacht werden.
Funktionsbaustein für den Solar-log um über Modbus TCP an die Daten zu kommen:
Und da ich dann auch im FB für den Solar-log die UNIX Zeit in DTL umwandeln musste und nirgends ein Baustein gerade Griffbereit hatte, griff ich auf Wikipedia zu und formte den Code in einen SCL Baustein um und falls den Jemand mal in Zukunft braucht dann kann er sich auch hier verweilen:
Gruß
Jürgen
erst einmal möchte ich Danke sagen an @Blockmove, der mit einem kleinen Denkanstoß dafür sorgte, dass ich mir mal schnell Gedanken machte über meine Solaranlage. Man muss dazu sagen, dass dieses Projekt erst ging, nachdem ich meinen Solar-log 500 über die Firmware 2.8.1 Build 49 gezogen hatte, aktuell Firmware 3.6.0 Build 99. Dadurch hatte ich Zugriff auf Modbus TCP. Ich habe die Bausteine nur mit der S7-1500 gemacht, bei anderen Steuerungen müssen eben Anpassungen gemacht werden.
Funktionsbaustein für den Solar-log um über Modbus TCP an die Daten zu kommen:
Code:
FUNCTION_BLOCK "Solarlog"
TITLE = Solarlog500
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : Juergen
VERSION : 0.1
VAR_INPUT
Modbus_REQ : Bool; // Activates the requested transmission if TRUE
Modbus_Disconnect : Bool; // Initiates a disconnect operation
Modbus_Mode : USInt; // Specifies the type of request: read, write or diagnostic
Modbus_Data_Addr : UDInt; // Specifies the starting address of the data to be accessed in the Modbus client
Modbus_Data_LEN : UInt; // Specifies the number of bits or words to be accessed
Modbus_InterfaceId : UInt; // HW-identifier of IE-interface submodule
Modbus_ID : CONN_OUC; // connection reference / identifier
Modbus_ConnectionType : Byte; // type of connection: 11=TCP/IP, 19=UDP (17=TCP/IP)
Modbus_ActiveEstablished : Bool; // active/passive connection establishment
Modbus_RemotePort : UInt; // remote UDP/TCP port number
"TCPIP_V4_Addr[1]" : Byte; // Remote IP Addr 1 (IPv4)
"TCPIP_V4_Addr[2]" : Byte; // Remote IP Addr 2 (IPv4)
"TCPIP_V4_Addr[3]" : Byte; // Remote IP Addr 3 (IPv4)
"TCPIP_V4_Addr[4]" : Byte; // Remote IP Addr 4 (IPv4)
END_VAR
VAR_OUTPUT
Modbus_Done : Bool; // Instruction finished without error
Modbus_Busy : Bool; // Modbus transaction in progress
Modbus_Error : Bool; // Instruction finished with error
Modbus_Status : Word; // Detailed error information
"lastUpdateTime_Unix-Format" : UDInt; // Unixtime, wann das letzte Registerupdate erfolgt ist. 0=noch keine Live-Daten (Einheit = Sec)
"lastUpdate_DT-Format" {InstructionName := 'DTL'; LibVersion := '1.0'} : DTL; // DT-Format, wann das letzte Registerupdate erfolgt ist. 0=noch keine Live-Daten (Einheit = DT-Format)
Pac : UDInt; // Gesamte Leistung Pac von allen Wechselrichtern und Zählern im Wechselrichtermodus (Einheit = W)
Pdc : UDInt; // Gesamte Leistung Pdc von allen Wechselrichtern (Einheit = W)
Uac : UInt; // Durchschnittliche Spannung Uac aller Wechselrichter (Einheit = V)
Udc : UInt; // Durchschnittliche Spannung Udc aller Wechselrichter (Einheit = V)
"Daily yield" : UDInt; // Summierter Tagesertrag aller Wechselrichter (Einheit = Wh)
"Yesterday yield" : UDInt; // Summierter gestriger Tagesertrag aller Wechselrichter (Einheit = Wh)
"Monthly yield" : UDInt; // Summierter Monatsertrag aller Wechselrichter (Einheit = Wh)
"Yearly yield" : UDInt; // Summierter Jahresertrag aller Wechselrichter (Einheit = Wh)
"Total yield" : UDInt; // Gesamtertrag aller Wechselrichter (Einheit = Wh)
"Pac consumption" : UDInt; // momentaner Gesamtverbrauch Pac aller Verbrauchszähler (Einheit = W)
"Daily yield consumption" : UDInt; // Summierter Tages-Verbrauch aller Verbrauchszähler (Einheit = Wh)
"Yesterday yield consumption" : UDInt; // Summierter Verbrauch des gestrigen Tages; alle Verbrauchszähler (Einheit = Wh)
"Monthly yield consumption" : UDInt; // Summierter Verbrauch des Monats; alle Verbrauchszähler (Einheit = Wh)
"Yearly yield consumption" : UDInt; // Summierter Verbrauch des Jahres; alle Verbrauchszähler (Einheit = Wh)
"Total yield consumption" : UDInt; // Summierter Gesamtverbrauch; alle Verbrauchszähler (Einheit = Wh)
TotalPower : UDInt; // Installierte Generatorleistung (Einheit = Wh/Wp)
END_VAR
VAR
MB_CLIENT_Instance {InstructionName := 'MB_CLIENT'; LibVersion := '5.2'} : MB_CLIENT;
Modbus_Connection {InstructionName := 'TCON_IP_v4'; LibVersion := '1.0'} : TCON_IP_v4 := (64, 1, (), true, ([()]), 502, ());
RAW_DATA { S7_SetPoint := 'True'} : Array[0..31] of UInt;
END_VAR
VAR_TEMP
Sekunden_Pro_Tag : UDInt;
Tage_im_Gemeinjahr : UDInt;
Tage_in_4_Jahren : UDInt;
Tage_in_100_Jahren : UDInt;
Tage_in_400_Jahren : UDInt;
TagN_AD_1970_01_01 : UDInt;
TagN : UDInt;
Sekunden_seit_Mitternacht : UDInt;
temp : UDInt;
tJahr : UDInt;
tMonat : UDInt;
tTag : UDInt;
tStunde : UDInt;
tMinute : UDInt;
tSekunde : UDInt;
END_VAR
BEGIN
// Initialisierung
//ModBus-Parameter
#Modbus_Connection.InterfaceId := #Modbus_InterfaceId;
#Modbus_Connection.ID := #Modbus_ID;
#Modbus_Connection.ConnectionType := #Modbus_ConnectionType;
#Modbus_Connection.ActiveEstablished := #Modbus_ActiveEstablished;
//TCPIP_Adresse initialisieren
#Modbus_Connection.RemoteAddress.ADDR[1] := #"TCPIP_V4_Addr[1]";
#Modbus_Connection.RemoteAddress.ADDR[2] := #"TCPIP_V4_Addr[2]";
#Modbus_Connection.RemoteAddress.ADDR[3] := #"TCPIP_V4_Addr[3]";
#Modbus_Connection.RemoteAddress.ADDR[4] := #"TCPIP_V4_Addr[4]";
//ModBus-Daten lesen
#MB_CLIENT_Instance(REQ:=#Modbus_REQ,
DISCONNECT:=#Modbus_Disconnect,
MB_MODE:=#Modbus_Mode,
MB_DATA_ADDR:=#Modbus_Data_Addr,
MB_DATA_LEN:=#Modbus_Data_LEN,
DONE=>#Modbus_Done,
BUSY=>#Modbus_Busy,
ERROR=>#Modbus_Error,
STATUS=>#Modbus_Status,
MB_DATA_PTR:=#RAW_DATA,
CONNECT:=#Modbus_Connection);
//--------------------- Solarlog RAW-Daten richtig einordnen ---------------------
//
//Unix-Zeitstempel einlesen (Einheit = Sec)
#"lastUpdateTime_Unix-Format".%W0 := #RAW_DATA[0];
#"lastUpdateTime_Unix-Format".%W1 := #RAW_DATA[1];
//Gesamtleistung Pac aller Wechselrichter einlesen (Einheit = W)
#Pac.%W0 := #RAW_DATA[2];
#Pac.%W1 := #RAW_DATA[3];
//Gesamtleistung Pdc aller Wechselrichter einlesen (Einheit = W)
#Pdc.%W0 := #RAW_DATA[4];
#Pdc.%W1 := #RAW_DATA[5];
//Durchschnittliche Spannung Uac aller Wechselrichter einlesen (Einheit = V)
#Uac := #RAW_DATA[6];
//Durchschnittliche Spannung Udc aller Wechselrichter einlesen (Einheit = V)
#Udc := #RAW_DATA[7];
//Summierter Tagesertrag aller Wechselrichter einlesen (Einheit = Wh)
#"Daily yield".%W0 := #RAW_DATA[8];
#"Daily yield".%W1 := #RAW_DATA[9];
//Summierter gestriger Tagesertrag aller Wechselrichter einlesen (Einheit = Wh)
#"Yesterday yield".%W0 := #RAW_DATA[10];
#"Yesterday yield".%W1 := #RAW_DATA[11];
//Summierter Monatsertrag aller Wechselrichter einlesen (Einheit = Wh)
#"Monthly yield".%W0 := #RAW_DATA[12];
#"Monthly yield".%W1 := #RAW_DATA[13];
//Summierter Jahresertrag aller Wechselrichter einlesen (Einheit = Wh)
#"Yearly yield".%W0 := #RAW_DATA[14];
#"Yearly yield".%W1 := #RAW_DATA[15];
//Gesamtertrag aller Wechselrichter einlesen (Einheit = Wh)
#"Total yield".%W0 := #RAW_DATA[16];
#"Total yield".%W1 := #RAW_DATA[17];
//Momentaner Gesamtverbrauch Pac aller Verbrauchszaehler einlesen (Einheit = W)
#"Pac consumption".%W0 := #RAW_DATA[18];
#"Pac consumption".%W1 := #RAW_DATA[19];
//summierter Tagesverbrauch aller Verbrauchszaehler einlesen (Einheit = Wh)
#"Daily yield consumption".%W0 := #RAW_DATA[20];
#"Daily yield consumption".%W1 := #RAW_DATA[21];
//summierter gestriger Tagesverbrauch aller Verbrauchszaehler einlesen (Einheit = Wh)
#"Yesterday yield consumption".%W0 := #RAW_DATA[22];
#"Yesterday yield consumption".%W1 := #RAW_DATA[23];
//summierter Monatsverbrauch aller Verbrauchszaehler einlesen (Einheit = Wh)
#"Monthly yield consumption".%W0 := #RAW_DATA[24];
#"Monthly yield consumption".%W1 := #RAW_DATA[25];
//summierter Jahresverbrauch aller Verbrauchszaehler einlesen (Einheit = Wh)
#"Yearly yield consumption".%W0 := #RAW_DATA[26];
#"Yearly yield consumption".%W1 := #RAW_DATA[27];
//summierter Gesamtverbrauch aller Verbrauchszaehler einlesen (Einheit = Wh)
#"Total yield consumption".%W0 := #RAW_DATA[28];
#"Total yield consumption".%W1 := #RAW_DATA[29];
//installierte Generatorleistung einlesen (Einheit = Wh/Wp)
#TotalPower.%W0 := #RAW_DATA[30];
#TotalPower.%W1 := #RAW_DATA[31];
//Unix-Zeitstempel in DT-Format wandeln
//
//Initialisierung
#Sekunden_Pro_Tag := 86400; // 24h * 60m * 60s
#Tage_im_Gemeinjahr := 365; //kein Schaltjahr
#Tage_in_4_Jahren := #Tage_im_Gemeinjahr * 4 + 1; // 4 * 365 +1
#Tage_in_100_Jahren := #Tage_im_Gemeinjahr * 100 + 25 - 1; // 100 * 365 + 25 - 1
#Tage_in_400_Jahren := #Tage_im_Gemeinjahr * 400 + 100 - 4 + 1; // 400 * 365 + 100 - 4 + 1
#TagN_AD_1970_01_01 := 719468; //Tagnummer bezogen auf den 1. Maerz des Jahres "Null"
//------------------------------------------------------------------------------------------------------
#TagN := #TagN_AD_1970_01_01 + #"lastUpdateTime_Unix-Format" / #Sekunden_Pro_Tag;
#Sekunden_seit_Mitternacht := #"lastUpdateTime_Unix-Format" MOD #Sekunden_Pro_Tag;
//Schaltjahrregel des Gregorianischen Kalenders
//Jedes durch 100 teilbare Jahr ist kein Schaltjahr, es sei denn, es ist durch 400 teilbar
#temp := 4 * (#TagN + #Tage_in_100_Jahren + 1) / #Tage_in_400_Jahren - 1;
#tJahr := 100 * #temp;
#TagN -= #Tage_in_100_Jahren * #temp + #temp / 4;
//Schaltjahrregel des Julianischen Kalenders
//Jedes durch 4 teilbare Jahr ist ein Schaltjahr
#temp := 4 * (#TagN + #Tage_im_Gemeinjahr + 1) / #Tage_in_4_Jahren - 1;
#tJahr += #temp;
#TagN -= #Tage_im_Gemeinjahr * #temp + #temp / 4;
//TagN enthaelt jetzt nur noch die Tage des errechneten Jahres bezogen auf den 1. Maerz
#tMonat := (5 * #TagN + 2) / 153;
#tTag := #TagN - (#tMonat * 153 + 2) / 5 + 1;
//153 = 31 + 30 + 31 + 30 + 31 Tage fuer die 5 Monate von Maerz bis Juli
//153 = 31 + 30 + 31 + 30 + 31 Tage fuer die 5 Monate von August bis Dezember
// 31 + 28 Tage fuer Januer und Februar (siehe unten)
//+2: Justierung der Rundung
//+1: Der erste Tag im Monat ist 1 (und nicht 0)
#tMonat += 3; // vom Jahr, das am 1. Maerz beginnt auf unser normales Jahr umrechnen
IF (#tMonat > 12) THEN
//Monate 13 und 14 entsprechen 1 (Januar) und 2 (Februar) des naechsten Jahres
#tMonat -= 12;
#tJahr += #tJahr;
END_IF;
#tStunde := #Sekunden_seit_Mitternacht / 3600;
#tMinute := #Sekunden_seit_Mitternacht MOD 3600 / 60;
#tSekunde := #Sekunden_seit_Mitternacht MOD 60;
//DTL zusammenbauen
#"lastUpdate_DT-Format".YEAR := UDINT_TO_UINT(#tJahr);
#"lastUpdate_DT-Format".MONTH := UDINT_TO_USINT(#tMonat);
#"lastUpdate_DT-Format".DAY := UDINT_TO_USINT(#tTag);
#"lastUpdate_DT-Format".HOUR := UDINT_TO_USINT(#tStunde);
#"lastUpdate_DT-Format".MINUTE := UDINT_TO_USINT(#tMinute);
#"lastUpdate_DT-Format".SECOND := UDINT_TO_USINT(#tSekunde);
END_FUNCTION_BLOCK
Und da ich dann auch im FB für den Solar-log die UNIX Zeit in DTL umwandeln musste und nirgends ein Baustein gerade Griffbereit hatte, griff ich auf Wikipedia zu und formte den Code in einen SCL Baustein um und falls den Jemand mal in Zukunft braucht dann kann er sich auch hier verweilen:
Code:
FUNCTION "Unixzeit_Nach_DTL" : Void
TITLE = Unixzeit_Nach_DTL
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : Juergen
VERSION : 0.1
VAR_INPUT
Unixtime : UDInt;
END_VAR
VAR_OUTPUT
Datum_Uhrzeit {InstructionName := 'DTL'; LibVersion := '1.0'} : DTL;
END_VAR
VAR_TEMP
Sekunden_Pro_Tag : UDInt;
Tage_im_Gemeinjahr : UDInt;
Tage_in_4_Jahren : UDInt;
Tage_in_100_Jahren : UDInt;
Tage_in_400_Jahren : UDInt;
TagN_AD_1970_01_01 : UDInt;
TagN : UDInt;
Sekunden_seit_Mitternacht : UDInt;
temp : UDInt;
tJahr : UDInt;
tMonat : UDInt;
tTag : UDInt;
tStunde : UDInt;
tMinute : UDInt;
tSekunde : UDInt;
END_VAR
BEGIN
//Initialisierung
#Sekunden_Pro_Tag := 86400; // 24h * 60m * 60s
#Tage_im_Gemeinjahr := 365; //kein Schaltjahr
#Tage_in_4_Jahren := #Tage_im_Gemeinjahr * 4 +1; // 4 * 365 +1
#Tage_in_100_Jahren := #Tage_im_Gemeinjahr * 100 + 25 - 1; // 100 * 365 + 25 - 1
#Tage_in_400_Jahren := #Tage_im_Gemeinjahr * 400 + 100 - 4 + 1; // 400 * 365 + 100 - 4 + 1
#TagN_AD_1970_01_01 := 719468; //Tagnummer bezogen auf den 1. Maerz des Jahres "Null"
//------------------------------------------------------------------------------------------------------
#TagN := #TagN_AD_1970_01_01 + #Unixtime / #Sekunden_Pro_Tag;
#Sekunden_seit_Mitternacht := #Unixtime MOD #Sekunden_Pro_Tag;
//Schaltjahrregel des Gregorianischen Kalenders
//Jedes durch 100 teilbare Jahr ist kein Schaltjahr, es sei denn, es ist durch 400 teilbar
#temp := 4 * (#TagN + #Tage_in_100_Jahren + 1) / #Tage_in_400_Jahren - 1;
#tJahr := 100 * #temp;
#TagN -= #Tage_in_100_Jahren * #temp + #temp / 4;
//Schaltjahrregel des Julianischen Kalenders
//Jedes durch 4 teilbare Jahr ist ein Schaltjahr
#temp := 4 * (#TagN + #Tage_im_Gemeinjahr + 1) / #Tage_in_4_Jahren - 1;
#tJahr += #temp;
#TagN -= #Tage_im_Gemeinjahr * #temp + #temp / 4;
//TagN enthaelt jetzt nur noch die Tage des errechneten Jahres bezogen auf den 1. Maerz
#tMonat := (5 * #TagN + 2) / 153;
#tTag := #TagN - (#tMonat * 153 + 2) / 5 + 1;
//153 = 31 + 30 + 31 + 30 + 31 Tage fuer die 5 Monate von Maerz bis Juli
//153 = 31 + 30 + 31 + 30 + 31 Tage fuer die 5 Monate von August bis Dezember
// 31 + 28 Tage fuer Januer und Februar (siehe unten)
//+2: Justierung der Rundung
//+1: Der erste Tag im Monat ist 1 (und nicht 0)
#tMonat += 3; // vom Jahr, das am 1. Maerz beginnt auf unser normales Jahr umrechnen
IF (#tMonat>12) THEN
//Monate 13 und 14 entsprechen 1 (Januar) und 2 (Februar) des naechsten Jahres
#tMonat -= 12;
#tJahr += #tJahr;
END_IF;
#tStunde := #Sekunden_seit_Mitternacht / 3600;
#tMinute := #Sekunden_seit_Mitternacht MOD 3600 / 60;
#tSekunde := #Sekunden_seit_Mitternacht MOD 60;
//Date and Time zusammenbauen
#Datum_Uhrzeit.YEAR := UDINT_TO_UINT(#tJahr);
#Datum_Uhrzeit.MONTH := UDINT_TO_USINT(#tMonat);
#Datum_Uhrzeit.DAY := UDINT_TO_USINT(#tTag);
#Datum_Uhrzeit.HOUR := UDINT_TO_USINT(#tStunde);
#Datum_Uhrzeit.MINUTE := UDINT_TO_USINT(#tMinute);
#Datum_Uhrzeit.SECOND := UDINT_TO_USINT(#tSekunde);
END_FUNCTION
Gruß
Jürgen