Umrechnen einer Temperatur in 2 Hexwerte (10er und 1er)

Hallo,

ich habe folgendes Skript geschrieben, und kann damit an meine Multiroomanlage Texte Senden, die dann auf allen Display´s im Haus angezeigt werden.
Nun möchte ich gern die Aussentemperatur anzeigen lassen, ist aber schwierig, da ich der Anlage jedes Zeichen einzeln als Hexcode senden muss, also nicht 20°C senden kann, sondern 2 und 0 senden muss, das ganze als Ascii Code im Hex Format. Kann mir jemand helfen, wie ich nun eine Variable (temp_max, Integer) so umrechne und aufteile

Hier mein Skript:

$array = explode(" ", "F0 7F 00 00 00 00 70 00 02 01 01 00 00 00 01 00 10 00 00 00 00 zz zz 27 43 00 00 00 00 00 00 00 00 00 cs F7");
$ID = 61660; //ComPort ID  in IPS
$array[21] = "31"; //Temperatur 10er, hier jetzt 1
$array[22] = "39"; //Temperatur 1er, hier jetzt 9
$summe = 0;
$ComString ="";

for ($i=0; $i<=count($array) - 3; $i++){
  $summe = $summe + hexdec($array[$i]);  //Step #1 - Add the HEX value of every byte in the message that precedes the Checksum:
  $ComString .= chr(hexdec($array[$i]));        //String zusammenfgen
}
$summe = $summe + count($array) -2;    //Step #2 - Count the number of bytes which precede the Checksum
$cs = $summe % 128;                 //This value is then AND-ed with the HEX value 0x007F
$ComString.=chr($cs).chr(hexdec(end($array)));        //String zusammenfgen

ComPort_SendText($ID, $ComString);      //String ausgeben

Hi,
das folgende Beispiel wäre auch eine elegante Lösung.
Die Antwort wie du den Temperaturwert einfügen kannst, findest du in den Zeilen 13 & 14.

<?
function HexDecArray(&$item, $key) {
    $item=hexdec($item);
}
function ChrArray(&$item, $key) {
    $item=chr($item);
}
function SendMultiroomTemperature($MultiroomID,$Temp) {
   //Commandstring OHNE Checksum und Endbyte
   $str ="F07F0000000070000201010000000100100000000000002743000000000000000000";
   $str=str_split($str,2);array_walk($str,"HexDecArray");
   //Temperaturwert ins String umwandeln & einfügen
   $Temp=($Temp<10) ? "0".(string)$Temp : (string)$Temp;
   $str[21]=ord(substr($Temp,0,1));$str[22]=ord(substr($Temp,1,1));
   //Checksum berechnen und Endbyte
   $str[34]=(array_sum($str)+count($str))%128;$str[35]=0xf7;
   array_walk($str,"ChrArray");$str=implode("",$str);
   ComPort_SendText($MultiroomID, $str);
}

//Aufruf:
SendMultiroomTemperature(61660,19);

?>

Viel Spass beim Ausprobieren! :slight_smile:
Günter.

Hallo Overkill0815,

Du machst Deinem Namen alle Ehre ;). Das von Dir gezeigte Skriptfragment würde ich auch als Overkill bezeichnen :D.

Es geht auch völlig ohne langwierige Array-Funktionen (explode, count, …) und zeitaufwändige Zahlenwandlungen (hexdec).
Wenn man den Ausgabestring gleich mit Hexadezimalwerten füttert, gibt es nichts zu wandeln.

Da die Temperatur als String vorliegt, gibt es auch hier keinen Grund diese erst in Hexadezimalzahlen zu wandeln.

Ein String kann übrigens oft wie ein Array behandelt werden.

$s1 = "\xf0\x7F\x00\x00\x00\x00\x70\x00\x02\x01\x01\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00";
$s2 = "°C\x00\x00\x00\x00\x00\x00\x00\x00\x00";
$temp = "19";                  // Temperatur liegt als String vor
$ComString = $s1. $temp. $s2;  // String zusammensetzen
$cs = strlen($ComString);      // Summe mit Anzahl der Zeichen vorbelegen
for ($i=0; $i<strlen($ComString); $i++)
  $cs += ord($ComString[$i]);  // zur Checksummenbildung alle Zeichen auf die bisherige Summe aufaddieren
$cs &= 0x7f;                   // Checksumme auf 7 bit reduzieren (AND)
$ComString .= $cs. chr(0xf7);  // Checksumme und Ende-Zeichen (F7) an den String anfügen

Falls die Temperatur als Integer vorliegt, kann sie mit folgender Funktion in einen dreistelligen String inkl. Vorzeichen gewandelt werden:

$temp = sprintf("%-3d", $Temperatur);

Gruß
HJH

@ HJH

Kann sein das es komliziert ist, aber es funktioniert :slight_smile:

zu deinem Skript, damit ist mein Problem nicht gelöst, denke ich, denn die umrechnung in 2 einzelne Hexwerte erfolgt nicht, oder? Angenommen Temp ist 20, dann wird 20 bei dir eingefügt, was im Ascii Code einem leerzeichen entspricht, ich bräuchte aber eine 2 als Hex und eine 0 als Hex.

Oder versteh ich dein Skript nur nicht?

Gruß
Benny

Hallo Benny,

selbstverständlich ist es das Wichtigste, dass ein Skript funktioniert. Da gebe ich Dir völlig Recht.

Aber gehen wir mal Dein Skript durch:
Nach der Explosion enthält Dein Array an jeder Position Strings mit jeweils 2 Zeichen.
Der String an der Position 0 lautet z.B.: „F0“. Das sind zwei Zeichen („F“ und „0“).
Du ersetzt nun die beiden Positionen 21 und 22 (bisher jeweils „zz“) durch „31“ und „39“.
Die Position 21 enthält jetzt einen zweistelligen String mit den Hex-Codes: 0x33 und 0x31 (= „31“).
Die Position 22 enthält dagegen die Hex-Codes: 0x33 und 0x39 (= „39“).
In der ersten FOR-Schleife werden die 2-stelligen Strings in 1-byte große Zahlen umgewandelt.
Durch die Funktion hexdec() wird aus dem String „31“ also die dezimale Zahl 49, welche absolut identisch ist mit der Hexzahl 0x31.
Ebenso wird auf dem selben Wege aus dem String „39“ die dezimale Zahl 57, die wiederum mit der Hexzahl 0x39 identisch ist.
An den Positionen 21 und 22 steht jetzt also der zweistellige String „19“ (0x31, 0x39).

Danach wird an dem String nichts mehr geändert.

In meinem Skript wird direkt der String „19“ eingefügt. In $ComString stehen also an den Positionen 21 und 22 die Hexzahlen 0x31 und 0x39. Es steht also sofort das drin, was bei Deinem Skript erst nach explode und hexdec zustande gekommen ist. Es ist also exakt dasselbe, nur ohne Umwege.

Wie Du siehst, ist die von Dir vermisste Wandlung völlig überflüssig. Du kannst die Temperatur also im „Klartext“ einfügen, wenn Du von meiner Methode der String-Erstellung ausgehst.

Gruß
HJH

@ HJH

Du hast das Problem noch nicht erfasst, glaube ich:

Der gesamte Code wird der Anlage geschickt, und die Übersetzt dann in Ascii Zeichen( ab der 21.sten stelle, die Stellen vorher sind zur Konfiguration wo die Zeichen im Display stehen), an der zz zz Position sind nun die Ersten beiden Zeichen im Display, in meinem Fall Position 21 ist \x31 (das enspricht dem Ascii Zeichen „1“) und Position 22 ist \x39 (das entspricht dem Ascii Zeichen „9“).

In deinem Fall wird ja einfach die 19 zwischen die beiden String teile geschoben, und dann würde meine Anlage das als \x19 interpretieren, was einem ganz anderen Zeichen in Ascii entspricht.

Ich möchte jetzt einfach eine 2 stellige Temperatur aufgeteilt in 2 einzelne Zeichen, 10er und 1er stelle, und diese Ascii Zeichen dann in Hex umrechnen, um sie an der richtigen Stelle (pos 21 und 22) einfügen.

Also 2 stellige Temperatur --> 2 einzelne Ascii Zeichen --> 2 einzelne Hex Werte ----> Anlage versteht Hex werte und setzt wieder um in Ascii

Hoffe ich habe mich nicht wieder zu kompliziert ausgedrückt :wink:

Gruß
Benny

Hallo Benny,

ich glaube eher, dass Du es bist, der das Problem von hinten durch die Brust ins Auge anpackt. Aber die Unterscheidung zwischen Computer-interner und externer (lesbarer) Darstellung von Zahlen ist ein Verständnisproblem mit dem viele zu kämpfen haben. Glaube mir, es ist nicht so kompliziert, wie Du es Dir jetzt noch vorstellst.

Der gesamte Code wird der Anlage geschickt, und die Übersetzt dann in Ascii Zeichen( ab der 21.sten stelle, die Stellen vorher sind zur Konfiguration wo die Zeichen im Display stehen), an der zz zz Position sind nun die Ersten beiden Zeichen im Display, in meinem Fall Position 21 ist \x31 (das enspricht dem Ascii Zeichen „1“) und Position 22 ist \x39 (das entspricht dem Ascii Zeichen „9“).

Genau das habe ich auch gesagt, nur habe ich dazu die Worte etwas anders gewählt.

In deinem Fall wird ja einfach die 19 zwischen die beiden String teile geschoben, und dann würde meine Anlage das als \x19 interpretieren, was einem ganz anderen Zeichen in Ascii entspricht.

Hier müssen wir uns jetzt sehr exakt ausdrücken, damit klar wird, was gemeint ist.
Bei mir wird keineswegs einfach die 19 (Zahl) zwischen die beiden Stringteile geschoben, sondern „19“, was ein String ist und keine Zahl.

Die hexadezimale Repräsentation der Zahl 19 lautet: 0x13 (1 Byte).
Die hexadezimale Repräsentation des Strings „19“ lautet: 0x31, 0x39 (2 Bytes), was identisch ist mit dem ASCII-Code.

In Deinem String steht vor dem Absenden an den Positionen 21 und 22 die Bytefolge: 0x31, 0x39.
In meinem String steht an den Positionen 21 und 22 ohne irgendwelche Rechnerei exakt die selbe Bytefolge: 0x31, 0x39.
Beide repräsentieren den Klartext „19“.

Es sollte, glaube ich, jetzt klar sein, dass der String „19“ schon aus genau den zwei Hexwerten besteht, die Du mit viel Aufwand hin- und wieder zurückgerechnet hast: 0x31 und 0x39.

Dein Ergebnis ist mit meinem völlig identisch. Probier es doch einfach mal aus.

Gruß
HJH

@ HJH

Dein Skript funktioniert leider nicht, es gibt keine Fehlermeldung, aber die Anlage tut auch nichts.

Aber das Skript von Spawn funktioniert wunderbar, und auch die Anlage gibt die Werte auf dem Display wieder, einzig Negative Zahlen sind noch ein Problem, da muss ich noch was ändern…

Trotzdem danke euch für Eure Mühen!

Hast du den String denn auch gesendet? Im Script von HJH fehlt ja noch das ComPort_SendText, aber das hast du sicherlich schon bemerkt, oder? :stuck_out_tongue:

Doc

Das sollte einem schon zu Denken veranlassen.

Ich habe einige Scripte von HJH, die funktionieren alle.
Leider liegt es aber auch an der Kommunikation hier im Forum.

Fragen kostet ja nix :wink:

Hi overkill0815,

wie ich dir schon per PN gesagt habe, probiere es doch nocheinmal mit dem Codebeispiel von HJH, falls du es nicht schon getan hast. Es funktioniert „wirklich“!
Vertrau uns allen. :slight_smile:

Und sein Code ist auch wesentlich smarter als der von mir, im besonderen für deine Zwecke lt. deiner PN.

Hier nochmal ein vollständiges Beispiel:


$MultiroomID=61660;
$temp = sprintf("%-3d", GetValueInteger ("temp_max"));      // Temperatur auslesen

$s1 = "\xf0\x7F\x00\x00\x00\x00\x70\x00\x02\x01\x01\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00";
$s2 = "°C\x00\x00\x00\x00\x00\x00\x00\x00\x00";

$ComString = $s1. $temp. $s2;  // String zusammensetzen
$cs = strlen($ComString);      // Summe mit Anzahl der Zeichen vorbelegen
for ($i=0; $i<strlen($ComString); $i++)
  $cs += ord($ComString[$i]);  // zur Checksummenbildung alle Zeichen auf die bisherige Summe aufaddieren
$cs &= 0x7f;                   // Checksumme auf 7 bit reduzieren (AND)
$ComString .= $cs. chr(0xf7);  // Checksumme und Ende-Zeichen (F7) an den String anfügen

ComPort_SendText($MultiroomID, $ComString );      // Kommando senden  :-)

@HJH & Mods: verzeiht das nochmalige Posten des Skripts.

Gruß
Günter.