Umgang mit negativen Zahlen

Hallo zusammen

Ich stehe vor einem Problem im Umgang mit negativen Zahlen. Via PHP-script lese ich die Daten meiner Wärmepumpe aus. Aktuell sind draussen ja die Temperaturen unter Null aber die Daten meines Scriptes haben je nach verwendeter PHP-Version korrekte negative oder astronomisch hohe Werte.

Der script sie wie folgt aus:


<?php
//Variablendefinition
$ip = xxx.xxx.xxx.xxx;
$port = 8888;

// connecten
$socket = socket_create(AF_INET, SOCK_STREAM,0);
$connect = socket_connect($socket, $ip, $port) || exit("socket_connect fehlgeschlagen"); 

if ($connect != 1)
	echo "ERROR: Nicht verbunden mit der Wärmepumpe<br>";

// Daten holen
$msg = pack('N*',3004);
$send=socket_write($socket, $msg, 4); //3004 senden

$msg = pack('N*',0);
$send=socket_write($socket, $msg, 4); //0 senden 

socket_recv($socket,$Test,4,MSG_WAITALL);  // Lesen, sollte 3004 zurückkommen
$Test = unpack('N*',$Test);

socket_recv($socket,$Test,4,MSG_WAITALL); // Status
$Test = unpack('N*',$Test);
//printf('Status: %s <br>',implode($Test));

socket_recv($socket,$Test,4,MSG_WAITALL); // Länge der nachfolgenden Werte
$Test = unpack('N*',$Test);

$JavaWerte = implode($Test);

for ($i = 0; $i < $JavaWerte; ++$i)
{
  socket_recv($socket,$InBuff[$i],4,MSG_WAITALL);  // Lesen, sollte 3004 zurückkommen
  $daten_raw[$i] = implode(unpack('N*',$InBuff[$i]));
}
//socket wieder schliessen 
socket_close($socket);

//---------------------------------------------------------------------------	
//Temperaturen
echo ("N:".($daten_raw[10] /10).":"); //Vorlauf
echo (($daten_raw[11] /10).":"); //Rücklauf
echo (($daten_raw[12] /10).":"); //Rücklauf-Soll
echo (($daten_raw[13] /10).":"); //Rücklauf-Extern
echo (($daten_raw[21] /10).":"); //Fussboden-Vorlauf
echo (($daten_raw[22] /10).":"); //Fussboden-Rücklauf
echo (($daten_raw[24] /10).":"); //Radiator-Vorlauf
echo (($daten_raw[25] /10).":"); //Radiator-Rücklauf
echo (($daten_raw[15] /10).":"); //Aussentemp
echo (($daten_raw[16] /10).":"); //Mitteltemp
echo (($daten_raw[19] /10).":"); //Wärmequelle-Eintritt
echo (($daten_raw[20] /10).":"); //Wärmequelle-Austritt
echo (($daten_raw[17] /10).":"); //Brauchwasser-Ist
echo ($daten_raw[18] /10); //Brauchwasser-Soll

?>

Den Script oben rufe ich via IP-Symcon auf und übernehme den Antwortstring. Der script selber läuft aus diversen Gründen nicht auf IP-Symcon selber.

Nun das Problem:

  • Führe ich den Script auf einem Linux-Rechner (Debian 3.2.81-1, PHP Version 5.4.45-0+deb7u4) aus, sind die Daten korrekt. Man beachte die negatven roten Werte „-0.6“ und „-7.1“
N:44.7:40.1:41:41.1:32:32:43.7:43.1:1.7:[b]-0.6[/b]:1.1:[b]-7.1[/b]:42.8:50
  • Führe ich den Script auf einer Synology (PHP Version 5.6.23) aus, sind die negativen Temperaturen völlig falsch. Die Werte in rot sind plötzlich astronimisch hoch und nicht mehr negativ.
N:44.7:40.1:41:41.1:32:32:43.7:43.1:1.7:[b]429496729[/b]:1.1:[b]429496722.5[/b]:42.8:50

Frage: An was liegt das ? Warum liefert der identische Script so unterschiedliche Resulate, nur weil die „Umgebung“ anders ist ?

Besten Dank für eure Inputs.

Letraz

Hallo Letraz.

Schau doch mal, was bereits in $daten_raw[$i] eingetragen wird.
Also um die Suche einzugrenzen.

Und teil zum Testen nicht durch 10 in der Ausgabe.

Gruß
lueralba

Hi,
Sieht nach fehlerhafter typumsetzung aus, also neg. Werte werden als positive Werte zB dword bzw single erkannt

Gesendet von iPhone mit Tapatalk

Ist bestimmt ein LittleEndian/BigEndian Problem :slight_smile: Nimm mal L statt N im unpack Befehl.

paresy

Oder kleines L ?

http://php.net/manual/de/function.pack.php

Gruß
lueralba

Hallo zusammen

Besten Dank für eure Inputs. Leider hilft das alles nicht weiter.
Weder ein „L“ noch ein „l“ im unpack-Befehl bringen das gewünschte Ergebnis. Es wird noch schlimmer, da die anderen Werte dann auch komplett anders dargestellt werden.

Wenn ich „L“ verwende:

$daten_raw[$i] = implode(unpack('L*',$InBuff[$i]));

Ist das Ergbnis:

N:167778713.6:57049088:251664793.6:333873152:120802508.8:119124787.2:295285555.2:301996441.6:36909875.2:45298483.2:46976204.8:[b]426141286.3[/b]:416081510.4:409370624

Bei Verwendung von „l“:

$daten_raw[$i] = implode(unpack('l*',$InBuff[$i]));

sieht es folgendermassen aus:

N:167778713.6:60404531.2:-177831936:-97301299.2:119124787.2:119124787.2:-122467123.2:-127500288:36909875.2:45298483.2:46976204.8:[b]-3355443.3[/b]:-13415219.2:-20126105.6

Der gesuchte Wert (in rot) wäre jeweils korrekt mit „-0.3“. Da es heute wärmer ist als zur Post-Erstellung, gibt es nur noch eine negative Zahl.

Der Gegentest auf der Linux-Maschine (dort wo es ja funktioniert) brachte das Selbe Ergebnis, sobald ich etwas anderes als „N“ im Unpack-Befehl verwenden, werden die anderen Daten auch anders dargestellt.

Es muss also mit der verwendeten PHP Version zusammenhängen. Nur wenn man die release notes so durchliest, findet man (zumindest ich) nicht heraus, welche Änderung an pack/unpack zu diesem „neuen“ Verhalten führen.

@lueralba
Der Wert im $daten_raw[$i] ist einfach derjenige ohne /10 also aktuell 4294967293 statt 429496729.3

Es liess mir keine Ruhe. Ich habe noch etwas mit den Zahlenwerten gespielt. Herausgekommen ist erstaunliches:
Wenn der gesuchte Wert negativ sein soll, dann ist er um den Wert 4294967296 minus den abgefragten Wert der Wärmepumpe multipliziert mit -1 zu hoch.
(Das Erstaunlichste daran ist, dass ich das selber herausgefunden habe mit meinen beschränkten Mathe-Kenntnissen … :cool:)

Wie auch immer, dass 4294967296 auch das Ergebnis von 2 hoch 32 ist, deutet doch stark in Richtung eines binären Problems hin. Nach einigem strapazieren der Synapsen durch Gehirn-Jogging kam mir die Sache verdächtig bekannt vor: Bei der Abfrage von Negativwerten bei den 1-Wire Temperatursensoren muss ebenfalls etwas gerechnet werden: Vom gemessenen Temperaturwert muss 2 hoch 7 oder 128 abgezogen werden. Nur verstehe ich im aktuellen Problem nicht, warum das PHP-Versionsabhängig ist … :confused:

Nun gut, wir sind ja quadratisch, praktisch und pragmatisch veranlagt und deshalb baue ich jetzt einfach eine Prüfung und - falls notwendig eine Korrektur innerhalb der FOR-Schleife ein:

for ($i = 0; $i < $JavaWerte; ++$i)
{
  socket_recv($socket,$InBuff[$i],4,MSG_WAITALL);  // Lesen, sollte 3004 zurückkommen
  $daten_raw[$i] = implode(unpack('N*',$InBuff[$i]));

  //Korrektur von negativen Werten
  if ($daten_raw[$i] > 4290000000)
  {
    $daten_raw[$i] = ((4294967296 - $daten_raw[$i]) *(-1) );
  }
}

Das funktioniert zwar wie gewünscht, hat aber einen faden Beigeschmack … :eek:

N:40.6:38.5:40.8:32.2:32.9:32.9:44:43.9:1.9:2.4:1.8:[b]-0.3[/b]:50.5:50