Hallo
Da nun schon mehrere Leute per PM nach den Scripten gefragt haben poste ich sie mal. Die Scipte waren nie zur Veröffentlichung gedacht waren, daher ist daher einiges an Handarbeit nötig um es zum Laufen zu bringen. Insbesondere müssen alle in den Scripten vorkommenden Variablen händisch angelegt und die ID entsprechend angepasst werden.
Es ist also mehr als cookbook dann als fertige Lösung zu betrachten.
OK, beginnen wir mit dem anlegen eines Serial Ports mit folgenden Settings:
Der Serial Port gibt seine Daten an einen Cutter mit diesen Settings weiter
![serial.JPG](https://community.symcon.de/uploads/default/original/2X/c/c1f2877c309916ac3a268b8df2ca16937ae40308.jpeg)
von dort landen sie in einer Registervariable welche ihrerseits das Script „PIPCommunication“ als Ziel definiert hat.
Hier ist dann auch schon die erste Baustelle, alle im Script verwendeten Variablen müssen händisch angelegt werden. Die ID der variablen dann im Script entsprechend einpflegen.
Je nach Gusto auch noch passende Variablenprofile zuweisen.
<?
Switch ($_IPS['SENDER'])
{
Default:
// PRINT "PW: ".$_IPS['SENDER'];
break;
Case "RunScript":
Case "Execute":
# $PipCommand ="QMOD";
# $PipCommand ="QPIGS";
# $PipCommand ="QPIWS";
# $StringToSend=$PipCommand.calculate_common_crc16c($PipCommand).chr(0x0D);
# REGVar_SendText(29318 /*[PV\PIP2\PIPComunication\Register Variable]*/, $StringToSend);
Case "TimerEvent":
break;
Case "Variable":
$PipCommand = $_IPS['VALUE'];
$StringToSend=$PipCommand.calculate_common_crc16c($PipCommand).chr(0x0D);
# for any reason PIP does not accept CRC for this command.
# CRC calculation verified with http://www.zorc.breitbandkatze.de/crc.html
# correct CRC: 0xE2 0x0A
# but PIP2424HS want to get 0xE2 0x0B
if ($PipCommand == "POP02"){
$StringToSend = chr(0x50).chr(0x4F).chr(0x50).chr(0x30).chr(0x32).chr(0xE2).chr(0x0B).chr(0x0D);
}
REGVar_SendText(29318 /*[PV\PIP2\PIPComunication\Register Variable]*/, $StringToSend);
Case "WebFront":
Case "RegisterVariable":
$data = $_IPS['VALUE']; #leading "(" and tailing "<CR>" is cut in Regvar Cutter
$mycrc = calculate_common_crc16c(substr('('.$data,0,-2) ); # add tailing '(' and remove CRC
IF ($mycrc == substr($data,-2)) {
$datasets = explode(' ', $data); // luckily datasets are already separated by " "
if (strlen($data) == 3) {
if(substr($datasets[0],0,1) == 'P') SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,0);
if(substr($datasets[0],0,1) == 'S') SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,1);
if(substr($datasets[0],0,1) == 'L') {
if (GetValue(34552 /*[PV\PIP2\PIP Daten\Status\Lädt vom Netz]*/)) {
SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,7);
}
else {
SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,2);
}
}
if(substr($datasets[0],0,1) == 'B') {
if (GetValue(55123 /*[PV\PIP1\PIP Daten\Batterie\Batteriestrom (berechnet)]*/) >=0) {
SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,6);
}
else {
SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,3);
}
}
if(substr($datasets[0],0,1) == 'F') SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,4);
if(substr($datasets[0],0,1) == 'H') SetValue(43888 /*[PV\PIP2\PIP Daten\Status\Betriebmodus]*/,5);
if(floatval(substr($datasets[0],0,1)) == 0) {
SetValue(59096 /*[PV\PIP2\PIP Daten\Status\Warning Status]*/,true);
}
else { SetValue(59096 /*[PV\PIP2\PIP Daten\Status\Warning Status]*/,false);
};
}
if (strlen($data) == 108) {
SetValueFloat(56990 /*[PV\PIP2\PIP Daten\Netz\Netzspannung]*/,floatval(substr($datasets[0],-5)));
SetValue(57460 /*[PV\PIP2\PIP Daten\Netz\Netzfrequenz]*/,floatval($datasets[1]));
SetValue(38633 /*[PV\PIP2\PIP Daten\Wechselrichter\Ausgangsspannung]*/,floatval($datasets[2]));
SetValue(20583 /*[PV\PIP2\PIP Daten\Wechselrichter\Ausgangsfrequenz]*/,floatval($datasets[3]));
SetValue(56087 /*[PV\PIP2\PIP Daten\Wechselrichter\Scheinleistung]*/,floatval($datasets[4]));
SetValue(48107 /*[PV\PIP2\PIP Daten\Wechselrichter\Wirkleistung]*/,floatval($datasets[5]));
SetValue(43847 /*[PV\PIP2\PIP Daten\Wechselrichter\Auslastung]*/,floatval($datasets[6]));
SetValue(18842 /*[PV\PIP2\PIP Daten\Wechselrichter\Busspannung]*/,floatval($datasets[7]));
SetValue(58966 /*[PV\PIP2\PIP Daten\Batterie\Batterie Spannung]*/,floatval($datasets[8])+0.1);
SetValue(36077 /*[PV\PIP2\PIP Daten\Batterie\Batterie Ladestrom]*/,floatval($datasets[9]));
SetValue(12611 /*[PV\PIP2\PIP Daten\Batterie\Batterie Ladezustand]*/,floatval($datasets[10]));
SetValue(35455 /*[PV\PIP2\PIP Daten\Temperatur]*/,((floatval($datasets[11])/10)-32)/1.8);
SetValue(22758 /*[PV\PIP2\PIP Daten\PV Daten\PV Strom]*/,floatval($datasets[12]));
SetValue(41090 /*[PV\PIP2\PIP Daten\PV Daten\PV Spannung]*/,floatval($datasets[13]));
SetValue(16415 /*[PV\PIP2\PIP Daten\Batterie\Batteriespannung SCC]*/,floatval($datasets[14]));
SetValue(15038 /*[PV\PIP2\PIP Daten\Batterie\Batterie Entladestrom]*/,floatval($datasets[15]));
SetValue(34552 /*[PV\PIP2\PIP Daten\Status\Lädt vom Netz]*/,($datasets[16] & 1));
SetValue(10814 /*[PV\PIP2\PIP Daten\Status\Lädt SCC]*/,($datasets[16] & 2));
SetValue(54850 /*[PV\PIP2\PIP Daten\Batterie\Batterieladung]*/,($datasets[16] & 4));
SetValue(33747 /*[PV\PIP2\PIP Daten\Status\Erhaltungsladung]*/,($datasets[16] & 8));
SetValue(57147 /*[PV\PIP2\PIP Daten\Status\Last Status]*/,($datasets[16] & 16));
}
if (strlen($data) == 95) {
SetValue(13546 /*[PV\PIP2\ReChargeVoltage]*/,floatval($datasets[8]));
SetValue(12376 /*[PV\PIP2\CutoffVoltage]*/,floatval($datasets[9]));
SetValue(35632 /*[PV\PIP2\ChargeBulkVoltage]*/,floatval($datasets[10]));
SetValue(38205 /*[PV\PIP2\PipChargeFloatVoltage]*/,floatval($datasets[11]));
SetValue(44355 /*[PV\PIP2\PipOutputMode]*/,floatval($datasets[16]));
SetValue(21765 /*[PV\PIP2\PipChargeMode]*/,floatval($datasets[17]));
SetValue(42940 /*[PV\PIP2\ReDischargeVoltage]*/,floatval($datasets[22]));
#print $datasets[16];
}
} #end CRC check
# for debug echo all datasets
/*for ($i = 0; $i < count($datasets) - 1; $i++)
{
echo "empfangener Datensatz: ".$datasets[$i]."
";
}
*/
}
#----------------------------------------------------------------------------------------------
// split buffer in byte and concatenate after CRC had been calculated
function calculate_common_crc16c($buffer)
{
$crc16c = 0x0; // the crc initial value
$buffer_length = strlen($buffer);
for ($i = 0; $i < $buffer_length; $i++)
{
$ch = ord($buffer[$i]);
$crc16c = update_common_crc16c($ch, $crc16c);
}
$data = (string) dechex($crc16c);
$len = strlen($data);
if($len % 2) {
$data = "0".$data; //substr($data, 0, $len -1);
}
return hex2bin($data);
}
// calculate the crc16c byte by byte
// $ch is the next byte and $crc16c is the result from the last call, or 0xffff initially
function update_common_crc16c($ch, $crc16c)
{
$crc16c_polynomial = 0x1021;
// This comment was in the code from
// http://www.joegeluso.com/software/articles/ccitt.htm
// Why are they shifting this byte left by 8 bits??
// How do the low bits of the poly ever see it?
$ch <<= 8;
for($i = 0; $i < 8; $i++)
{
if (($crc16c ^ $ch) & 0x8000)
{
$xor_flag = true;
}
else
{
$xor_flag = false;
}
$crc16c = $crc16c << 1;
if ($xor_flag)
{
$crc16c = $crc16c ^ $crc16c_polynomial;
}
$ch = $ch << 1;
}
// mask off (zero out) the upper two bytes
$crc16c = $crc16c & 0x0000ffff;
return $crc16c;
}
?>
Das obige Script erledigt zwei Dinge. Einerseits nimmt es die Daten welche der Wechselrichter sendet aus der Registervariable entgegen, zerlegt diese und schreibt die Werte in entsprechende Variablen.
Andererseits wird es von der Variable „CommandtoPip“ getriggert. Diese „CommandtoPip“ Variable wird ihrerseits zyklisch durch ein weiteres Script „PIP Command“ oder per Webfront mit Steuerkommandos für den Wechselrichter beschrieben.
Das „PipCommunication“ Script nimmt diese Klartextkommandos entgegen, berechnet den CRC und schickt sie an den Wechselrichter.
Das war es dann im wesentlichen auch schon wieder.
Das „PIPCommand“ Script sieht bei mir so aus:
<?
Switch ($_IPS['SENDER'])
{
Default:
break;
Case "RunScript":
Case "Execute":
#SetValueString (53394 /*[PV\PIP1\PIPCommand\CommandToPip]*/,"QVFW2"); # Mode
# $PipCommand ="QVFW";
# $PipCommand ="QPIGS";
# $PipCommand ="QPIWS";
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QFLAG"); # Mode
IPS_Sleep(400);
# SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QPIWS"); #Warning
# IPS_Sleep(400);
# SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QPIGS"); #Parameter
break;
Case "TimerEvent":
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QMOD"); # Mode
IPS_Sleep(300);
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QPIWS"); #Warning
IPS_Sleep(300);
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QPIGS"); #Parameter
break;
Case "Variable":
Case "WebFront":
# SetValue($_IPS['VARIABLE'], $_IPS['VALUE']);
if ($_IPS['VARIABLE'] == 44355 /*[PV\PIP2\PipOutputMode]*/) {
switch ($_IPS['VALUE'])
{
case 0:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"POP00");
break;
case 1:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"POP01");
break;
case 2:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"POP02");
break;
}
}
if ($_IPS['VARIABLE'] == 21765 /*[PV\PIP2\PipChargeMode]*/) {
switch ($_IPS['VALUE'])
{
case 0:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PCP00");
break;
case 1:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PCP01");
break;
case 2:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PCP02");
break;
case 3:SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PCP03");
break;
}
}
if ($_IPS['VARIABLE'] == 13546 /*[PV\PIP2\ReChargeVoltage]*/) {
$setpoint=number_format($_IPS['VALUE'],1);
# print "PBCV".$setpoint;
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PBCV".$setpoint);
}
if ($_IPS['VARIABLE'] == 42940 /*[PV\PIP2\ReDischargeVoltage]*/) {
$setpoint=number_format($_IPS['VALUE'],1);
#$setpoint = "00.0";
# print "PBDV".$setpoint;
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PBDV".$setpoint);
}
if ($_IPS['VARIABLE'] == 12376 /*[PV\PIP2\CutoffVoltage]*/) {
$setpoint=number_format($_IPS['VALUE'],1);
# print "PSDV".$setpoint;
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PSDV".$setpoint);
}
if ($_IPS['VARIABLE'] == 38205 /*[PV\PIP2\PipChargeFloatVoltage]*/) {
$setpoint=number_format($_IPS['VALUE'],1);
#echo $setpoint;
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PBFT".$setpoint);
}
if ($_IPS['VARIABLE'] == 35632 /*[PV\PIP2\ChargeBulkVoltage]*/) {
$setpoint=number_format($_IPS['VALUE'],1);
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"PCVV".$setpoint);
}
# Read back setting to see accepted
IPS_Sleep(500);
SetValueString (23017 /*[PV\PIP2\PIPCommand\CommandToPip]*/,"QPIRI"); #Parameter
}
?>
Auch dieses ist an die jeweiligen Bedürfnisse, Bspw. welche Daten nun wann abgefragt, oder welche Settings übers
Webfront eingestellt werden sollen anzupassen.
Die Objekthirachie sieht so aus:
Es müssen nur die markierten Objekte angelegt werden.
viele Erfolg
bb