Hallo Thomas,
vielen, vielen Dank für deine Scripte! Ich habe es tatsächlich damit hinbekommen, den Tagesertrag & Jahresertrag auszulesen.
Ich bastle im Moment noch weiter an den Scripten, ein kurzes Zwischenergebnis schon mal vorab hier.
Man braucht:
1x Serial Port I/O Instanz (19200,8,1,n)
1x Registervariable, verknüpft mit Serial Port
1x Registervariablenscript, verknüpft mit Registervariable (s.u.)
1x Wechselrichterkommandos Script (s.u.)
1x Konstantendefinitionsscript (Constants.php, angehängt)
5x Variablen:
1x string = adresse (enthält die Adresse des WR. der 1. WR hat die 2, der 2. WR die 3 usw.)
1x string = command (enthält das aufgerufene Kommando, z.B. „78“)
1x string = args (enthält ein oder mehrere Parameter des Kommandos, z.B. „3“)
1x bool = sperre_senden (enthält einen Bool Parameter, damit nicht mehrere Scripte gleichzeitig die Reg.Var vollschreiben)
1x string = transmission status (enthält das Ergebnis der Übertragungsstatus des Bus’)
1x string = var (enthält die ID der Variablen, an die das Ergebnis geschrieben werden soll)
Aufgerufen wird dann zum Beispiel die folgende Funktion:
getcumulatedenergy(52694, 2, CUMULATED_DAILY);
^^ die Funktion soll die Angabe über die vom Wechselrichter mit der ID2 über den Tag gesammelte Energie in die Symcon Variable mit der ID „52694“ schreiben.
Dazu brauchen wir also das Wechselrichter Kommando Script:
<?
include ('Constants.php');
$ComID = 26058 /*[Serial Port]*/;
function communicate ($var, $address, $command, $args) {
$data = "";
for ($i=0;count($args)+$i<6;$i++){
$data = $data."\x00";
}
$addresshex = chr($address);
$commandhex = chr($command);
$c = 1;
if (count($args)>1){
foreach ($args as $content){
$argshex[$c]= chr($content);
$c++;
}
}
if (count($args)==1){
$argshex= chr($args);
}
$FC =$addresshex.$commandhex.$argshex.$data; // Datenframe
$CRC = crc_ccitt($FC);
$CRC16str = chr($CRC>>8). chr($CRC&0xff);
$Senddata = $FC.$CRC16str;
$finished = false;
$i = 0;
while ( ! $finished )
{
$Sperre = GetValue(16398 /*[Energie\WR ransmission_bus\sperre_senden]*/);
if ($Sperre == false){
$finished = true;
}
// Timeout
if ($Sperre == true){
IPS_sleep(200);
}
$i++;
if ($i >= "10"){
$finished = true;
setvalue(16398 /*[Energie\WR ransmission_bus\sperre_senden]*/,false);
return "Error - ComPort in use?";
}
}
$Sperre = GetValue(16398 /*[Energie\WR ransmission_bus\sperre_senden]*/);
if ($Sperre == false);
{
$ComID = 26058 /*[Serial Port]*/;
setvalue(34044 /*[Energie\WR ransmission_bus\var]*/,$var);
setvalue(28973 /*[Energie\WR ransmission_bus\address]*/,$address);
setvalue(21813 /*[Energie\WR ransmission_bus\command]*/,$command);
setvalue(49633 /*[Energie\WR ransmission_bus\args]*/,$args); // noch kein Array - muss noch angepasst werden, da die Parameteranzahl ggf. größer 1
setvalue(16398 /*[Energie\WR ransmission_bus\sperre_senden]*/,true);
Comport_Sendtext($ComID, $Senddata);
}
}
// CRC function
function crc_ccitt($str)
// CRC für Aurora Power One Protokoll
// Thomas Unger 26.05.2011
//
//Checksum calculation
//The algorithm to compute the checksum to validate the RS485 transmission is the CRC polynomial
//standardized by CCITT:
//Bn=N^16+N^12+N^5+Bn-1
//Where N^16 means that N is elevated to the sixteenth power of 2 (i.e. it is shifted left of 16 bit)
//and where the symbol ‘+’ represents the XOR bit by bit.
//Practically, if New is the byte to process , Tmp is a swap byte and BccLo and BccHi are the low
//and high parts of the validation word, the following algorithm must be followed:
//A. Initialize BccLo=0xFF, BccHi=0xFF
//B. For each byte to transmit or receive repeat the following steps:
//1. New = New XOR BccLo
//2. Tmp=New << 4
//3. New=Tmp XOR New
//4. Tmp=New >> 5
//5. BccLo=BccHi
//6. BccHi= New XOR Tmp
//7. Tmp= New << 3
//8. BccLo= BccLo XOR Tmp
//9. Tmp= New >> 4
//10. BccLo= BccLo Xor Tmp
//C. Negate bit by bit BccLo e BccHi : CRC_L=~BccLo CRC_H=~BccHi
//
// 034E030000000000 F944 laut Internet korrekte Prüfsummen
// 024E030000000000 46C5
// 024E000000000000 3BC9
{
$BccLo = 0xFF;
$BccHi = 0xFF;
//$New=0;
for ($count=0; $count<strlen($str); $count++)
{
$New = ord($str[$count]) ^ $BccLo;
$Tmp = $New << 4;
$Tmp = $Tmp & 0xFF;
$New = $Tmp ^ $New;
$Tmp = $New >> 5;
$BccLo = $BccHi;
$BccHi= $New ^ $Tmp;
$Tmp = $New << 3;
$Tmp = $Tmp & 0xFF;
$BccLo = $BccLo ^ $Tmp;
$Tmp= $New >> 4;
$BccLo = $BccLo ^ $Tmp;
}
$CRC=((~$BccLo& 0xFF) << 8)|(~$BccHi& 0xFF);
return $CRC;
}
// This function is used to show the cumulated Energy in regards to the period
// period can be: CUMMULATED_DAILY, CUMMULATED_WEEKLY, CUMMUATED_MONTHLY,
// CUMMULATED_YEARLY, CUMMUALTED_TOTAL, CUMMULATED_PARTIAL;
function getCumulatedEnergy ($var, $address, $period){
communicate($var, $address, OP_GET_CUMULATED_ENERGY, $period, 0); // OP_GET_CUMULATED_ENERGY => 78;
}
function getDSPData ($var, $address, $parameter){
communicate($var, $address, OP_GET_DSP, $parameter, 0); //OP_GET_DSP => 59;
}
function hextostr($hex)
{
$str='';
for ($i=0; $i < strlen($hex)-1; $i+=2)
{
$str .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $str;
}
function strToHex($string)
{
$hex='';
for ($i=0; $i < strlen($string); $i++)
{
$hex .= dechex(ord($string[$i]));
}
return $hex;
}
?>
Und dann noch das Registervariablenscript:
<?
//structure of the answer has also fixed length (6 Bytes + 2 Bytes for Checksum) :
//0 1 2 3 4 5 6 7
//Transmission State Global State B2 B3 B4 B5 CRC_L CRC_H
//Global State:
//It shows the state of the addressed device, the details are specified in the
//description of the commands.
//Trans. State Global State Val3 Val2 Val1 Val0 CRC_L CRC_H
//The 4 bytes Val3 ... Val0 compose a float value. In order to rebuild the original float value it is
//necessary to put in sequence the 4 bytes and to read it according to the ANSI standard
if ($IPS_SENDER == "RegisterVariable")
{
// bereits im Puffer der Instanz vorhandene Daten in $data kopieren
$data = RegVar_GetBuffer($IPS_INSTANCE);
// neu empfangene Daten an $data anhängen
$data .= $IPS_VALUE;
echo "
data: ".$data;
echo "
datalen ".strlen($data)."
";
if (strlen($data) > 7)
{
$Adress_Slave = GetValue(28973 /*[Energie\WR ransmission_bus\address]*/);
$Command = GetValue(21813 /*[Energie\WR ransmission_bus\command]*/);
$Type = GetValue(49633 /*[Energie\WR ransmission_bus\args]*/);
//
// Status
//0 = Everything is OK.
//51 = Command is not implemented
//52 = Variable does not exist
//53 = Variable value is out of range
//54 = EEprom not accessible
//55 = Not Toggled Service Mode
//56 = Can not send the command to internal micro
//57 = Command not Executed
//58 = The variable is not available, retry
switch(ord($data[0]))
{
case 0:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "Everything is OK." );
break;
case 51:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "Command is not implemented" );
break;
case 52:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "Variable does not exist" );
break;
case 53:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "Variable value is out of range" );
break;
case 54:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "EEprom not accessible" );
break;
case 55:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "Not Toggled Service Mode" );
break;
case 56:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "an not send the command to internal micro" );
break;
case 57:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "Command not Executed" );
break;
case 58:
SetValue(12255 /*[Energie\WR ransmission_bus ransmission_status]*/ , "The variable is not available, retry" );
break;
}
switch($Command){
case 78:
$val = ((ord($data[2])*16777216)+(ord($data[3])*65536)+(ord($data[4])*256)+ord($data[5]))/1000;
setvalue(getvalue(34044 /*[Energie\WR ransmission_bus\var]*/),(float)$val);
break;
case 59:
$val = unpack("f", $data[5].$data[4].$data[3].$data[2]);
setvalue(getvalue(34044 /*[Energie\WR ransmission_bus\var]*/),(float)$val[1]);
break;
} // end Switch ($command)
// Puffer löschen
$data = '';
SetValue(16398 /*[Energie\WR ransmission_bus\sperre_senden]*/,"0");
setvalue(34044 /*[Energie\WR ransmission_bus\var]*/,0);
setvalue(28973 /*[Energie\WR ransmission_bus\address]*/,"");
setvalue(21813 /*[Energie\WR ransmission_bus\command]*/,"");
setvalue(49633 /*[Energie\WR ransmission_bus\args]*/,"");
ips_sleep(100); //Pause für neue Datenanforderung ?!
} // end if (strlen($data) > 7)
// Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
RegVar_SetBuffer($IPS_INSTANCE, $data);
} // end if ($IPS_SENDER == "RegisterVariable")
function strToHex($string)
{
$hex='';
for ($i=0; $i < strlen($string); $i++)
{
$hex .= dechex(ord($string[$i]));
}
return $hex;
}
?>
Da ist noch einiges optimierbar und erweiterbar, und bestimmt nicht die letzte Version.
Kommentare sind von allen gerne willkommen - bin neu in der PHP Programmierung und dankbar für Feedback.
Gruß,
Kai
Constants.zip (1.25 KB)