Problem mit negativen Integer Werten ...

Hallo ‚Freaks‘

Ich bräuchte Bitte mal kurz eure Unterstützung.

Ich habe seit dem Update auf IP-Symcon v5.0 ein Problem ein 4 Byte Array in eine Integer Zahl zu konvertieren wenn diese negativ wird.
Ich glaube, mein Problem liegt auf der Seite von PHP 7 welches IP-Symcon 5.0 verwendet.

Und zwar habe ich einen Smart Meter der mir den Leistungsfaktor (CosPhi) in einem 4 Byte Array liefert.


Zuerst mal ein Beispiel mit einer positiven Integer Zahl was auch auf PHP 7 problemlos funktioniert

Folgende 4 Bytes liefert mein Smart Meter:
$byte_array[0] = 0x00;
$byte_array[1] = 0x00;
$byte_array[2] = 0x02;
$byte_array[3] = 0xBA;

$value = ($byte_array[0]<<24) + ($byte_array[1]<<16) + ($byte_array[2]<<8) + ($byte_array[3]);
var_dump($value);

Ergebnis ist hier korrekt: int(698)  -> CosPhi ist also 698/1000 = 0.698


Habe ich aber eine PV-Einspeisung ist der Leistungsfaktor negativ. 
Mit IP-Symcon 4.x (und PHP 5.6) hat die selbe Umwandlung funktioniert. Mit PHP 7 gibt es aber jetzt ein Problem.

Folgende 4 Bytes liefert mein Smart Meter:
$byte_array[0] = 0xFF;
$byte_array[1] = 0xFF;
$byte_array[2] = 0xFE;
$byte_array[3] = 0x3C;

$Value = ($byte_array[0]<<24) + ($byte_array[1]<<16) + ($byte_array[2]<<8) + ($byte_array[3]);
var_dump($Value);

Ergebnis ist hier: int(4294966844)
Soll aber -451 sein -> CosPhi soll also -0.451 sein

Hat von euch wer eine Idee wie ich die 4 Bytes erfolgreich umwandeln kann sodass positive als auch negative Werte korrekt sind ???

Zusatz:
Spannend finde ich die Visualisierung in IP-Symcon v5.0
Setzte ich den Wert 4294966,844 in eine Float Variable und ‚doppelklicke‘ ich auf den Wert um diesen zu bearbeiten, wird in IP-Symcon der ‚korrekte‘ Negative Wert angezeigt !?!?

Das Variablenprofil dieser Float Variable sind so aus. Äderungen am Variablenprofil ändern hier aber auch nichts an der Anzeige …

Nicht PHP7 sondern der Umstieg auf 64Bit ist hier die Ursache.
IPS intern kann aber nur int bis 32Bit. Darum auch das Verhalten in der Konsole.

Hatten wir schon ein paar mal hier im Forum.

Anstatt sie Bytes selber zu schieben, würde ich einfach unpack nutzen.
Wobei es da eingangsseitig ein String und kein Array sein muss.

Michael

Schau dir mal den Befehl „unpack“ bei PHP an. Der kann das alles recht komfortabel :slight_smile:

paresy

Ich hab mich hier mit „unpack“ noch einmal mehrere Stunden beschäftigt, aber irgendwo habe ich ein Problem bzw. einen Fehler …

Zum Testen habe ich jetzt mal folgendes getestet:

Test 1 - mit „\xFF\xFF\xFE\x3C“


<?
$binarydata = "\xFF\xFF\xFE\x3C";

error_reporting(0);

// http://php.net/manual/de/function.pack.php
$formatting = array("a","A","h","H","c","C","s","S","n","v","i","I","l","L","N","V","q","Q","J","P","f","g","G","d","e","E","x","X","Z","@");

foreach($formatting as $format) {
    $value = unpack($format, $binarydata);
    echo "unpack format '".$format."' > ";
    $result = $value[1];
    $lastError = error_get_last();
    if($lastError != null) {
        echo "ERROR/WARNING: " . $lastError[message] . "
";
    } else {
        var_dump($result);
    }
}

?>

Ergebnis ist:


unpack format 'a' > string(1) "ÿ"
unpack format 'A' > string(1) "ÿ"
unpack format 'h' > string(1) "f"
unpack format 'H' > string(1) "f"
unpack format 'c' > int(-1)
unpack format 'C' > int(255)
unpack format 's' > int(-1)
unpack format 'S' > int(65535)
unpack format 'n' > int(65535)
unpack format 'v' > int(65535)
unpack format 'i' > int(1023344639)
unpack format 'I' > int(1023344639)
unpack format 'l' > int(1023344639)
unpack format 'L' > int(1023344639)
unpack format 'N' > int(4294966844)
unpack format 'V' > int(1023344639)
unpack format 'q' > ERROR/WARNING: unpack(): Type q: not enough input, need 8, have 4
unpack format 'Q' > ERROR/WARNING: unpack(): Type Q: not enough input, need 8, have 4
unpack format 'J' > ERROR/WARNING: unpack(): Type J: not enough input, need 8, have 4
unpack format 'P' > ERROR/WARNING: unpack(): Type P: not enough input, need 8, have 4
unpack format 'f' > ERROR/WARNING: Use of undefined constant message - assumed 'message' (this will throw an Error in a future version of PHP)
unpack format 'g' > ERROR/WARNING: Use of undefined constant message - assumed 'message' (this will throw an Error in a future version of PHP)
unpack format 'G' > ERROR/WARNING: Use of undefined constant message - assumed 'message' (this will throw an Error in a future version of PHP)
unpack format 'd' > ERROR/WARNING: unpack(): Type d: not enough input, need 8, have 4
unpack format 'e' > ERROR/WARNING: unpack(): Type e: not enough input, need 8, have 4
unpack format 'E' > ERROR/WARNING: unpack(): Type E: not enough input, need 8, have 4
unpack format 'x' > ERROR/WARNING: Undefined offset: 1
unpack format 'X' > ERROR/WARNING: Undefined offset: 1
unpack format 'Z' > ERROR/WARNING: Use of undefined constant message - assumed 'message' (this will throw an Error in a future version of PHP)
unpack format '@' > ERROR/WARNING: Undefined offset: 1


Test 2 - mit „\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x3C“


<?
$binarydata = "\xFF\xFF\xFF\xFF\xFF\xFF\xFE\x3C";

error_reporting(0);

// http://php.net/manual/de/function.pack.php
$formatting = array("a","A","h","H","c","C","s","S","n","v","i","I","l","L","N","V","q","Q","J","P","f","g","G","d","e","E","x","X","Z","@");

foreach($formatting as $format) {
    $value = unpack($format, $binarydata);
    echo "unpack format '".$format."' > ";
    $result = $value[1];
    $lastError = error_get_last();
    if($lastError != null) {
        echo "ERROR/WARNING: " . $lastError[message] . "
";
    } else {
        var_dump($result);
    }
}
?>

Ergebnis ist:


unpack format 'a' > string(1) "ÿ"
unpack format 'A' > string(1) "ÿ"
unpack format 'h' > string(1) "f"
unpack format 'H' > string(1) "f"
unpack format 'c' > int(-1)
unpack format 'C' > int(255)
unpack format 's' > int(-1)
unpack format 'S' > int(65535)
unpack format 'n' > int(65535)
unpack format 'v' > int(65535)
unpack format 'i' > int(-1)
unpack format 'I' > int(4294967295)
unpack format 'l' > int(-1)
unpack format 'L' > int(4294967295)
unpack format 'N' > int(4294967295)
unpack format 'V' > int(4294967295)
unpack format 'q' > int(4395231761336893439)
unpack format 'Q' > int(4395231761336893439)
unpack format 'J' > int(-452)
unpack format 'P' > int(4395231761336893439)
unpack format 'f' > float(NAN)
unpack format 'g' > float(NAN)
unpack format 'G' > float(NAN)
unpack format 'd' > float(6,883382752676E-15)
unpack format 'e' > float(6,883382752676E-15)
unpack format 'E' > float(NAN)
unpack format 'x' > ERROR/WARNING: Undefined offset: 1
unpack format 'X' > ERROR/WARNING: Undefined offset: 1
unpack format 'Z' > ERROR/WARNING: Use of undefined constant message - assumed 'message' (this will throw an Error in a future version of PHP)
unpack format '@' > ERROR/WARNING: Undefined offset: 1

Komisch:

  • Beim Test1 kommt nirgends das erwartetet Ergebnis von -452 aus!
  • Beim Test2 kommt ausgerechnet beim Formatzeichen ‚J‘ das Ergebnis -452 raus !??

‚J‘ ist aber laut PHP Doku ein „vorzeichenloser Long-Long-Typ (immer 64 bit, Byte-Folge Big Endian)“

Habt ihr eine Idee wo ich da was falsch mache oder falsch sehe …

Note: Ich verwende dabei IP-Symcon v5.0 auf Windows 10 Enterprise 64-Bit (mit 16GB RAM)
2018-08-26_163346.png