String über XBee senden und zerlegen

Hallo,

habe eine wohl ziemlich doofe Frage:

Ich habe einen zyklischen String (aktuell alle 10s) in der Art:
tempC:20.1;humid:60;voc:80;CRLF

Dieser String wird via XBee End Device übertragen an den Coordinator (Zieladresse = 0)

Coordinator MyId=0

MyId des End Device kann ich nicht selbst via X-CTU ändern, der wird blöderweise beim Join automatisch festelegt (… immer eine andere!!!)

Der Join klappt, --> Im Terminal des X-CTU kommen tatsächlich die Daten am Coordinator an, mit einigem an Hexcode davor und danach. (z.B. das CRLF am Ende)

Dann habe ich folgendes gemacht:

–> Serielle Schnittstelle in IPS angelegt mit den gleichen Einstellungen + aktiv gesetzt
–> XBee Gateway angelegt, Coordinator ID = 0, übergeordnete Instanz = Serielle Schnittstelle
–> XBee Splitter angelegt, Device ID = immer unterschiedlich je nach aktueller MyID jeweils von Hex in Dez gewandelt :mad:
–> Register Variable angelegt, übergeordnete Instanz = Splitter
–> Test-Script angelegt und in Registervariable als Ziel eingetragen
$daten = $IPS_VALUE;
IPS_LogMessage($IPS_SELF, $IPS_VALUE);

Nix passiert - garnichts… was mache ich falsch?
In X-CTU kommen doch auch Daten an ???!!!

Zerlege ich dann den String nach dem Splitter mit drei cuttern in temp, humid und voc??
Oder mit einem Cutter in den ganzen String und im Script dann den Rest???

Ich würde dann die drei Werte gerne in float Variablen mit zwei Kommastellen schreiben, diese jeweils loggen und als Graph ausgeben.

Komme irgendwie nicht weiter… :frowning:

Hi

hast den API Mode beim Coordinator-XBEE (via XCTU) aktiviert ?
Zufälligerweise hatte ich vor 1 Stunde das gleiche Problem.

gruß
bb

API ist aktiviert - beim X-CTU Terminal musste ich vorher das Häkchen bei API setzen.

Für IPS soll ja auch API Mode beim Coordinator aktiv sein, oder?

Ich habe den Coordinator mit XB24-ZB Version 2170 (Zigbee Coordinator API) laufen.

Hmm
weiß nicht warum du die Zigbee Firmware verwendest ? Obs da anders ist ??

Ich hab hier die XBP24 Firmware Function Set XBEE PRO 802.15.4 Vers. 10E8
API Enable=1 mußt auch in den Modem Settings aktivieren.
Nur das Häckchen im XCTU zu setzen reicht nicht.

gruß
bb

Habe gerade mal wieder getestet.

Auf dem com Port kommen die Daten an. (in IPS, com5, --> debug)
Erstmal ein wenig hexcode, dann tempC:20, dann ist das Paket zuende und im nächsten Paket steht der nächste Teilstring usw…
–> com5 = OK :slight_smile:

XBee Gateway mit Koordinator ID = 0 (die 16bit My Adr. des Coordinators steht auch auf 0)
Übergeordnete Instanz der funktionierende com-Port
Debugfenster = leer :confused:

XBee Splitter mit Gerät ID 37123dez (umgewandelt aus 0x9103h via X-CTU ausgelesen)
Übergeordnete Instanz Gateway
Debugfesnter = leer :confused:

  1. Wie kann ich eine feste 16bit MY-Adresse beim Enddevice angeben? X-CTU lässt dieses Feld nicht als Eingabefeld zu, sondern will den Wert dynamisch angeben. Ziemlich doff, wenn ich in IPS diese Adresse fest anlegen muss.

  2. Wie komme ich über Gateway und Splitter an die Daten des COM5?

  3. Wie setze ich die Teilstrings zu einem String bis CRLF zusammen?

  4. Wie schreibe ich diese Daten in Variablen, die ich loggen kann? (cutter oder Script?)

Ich habe nichts im Forumsbeitrag zu der Firmwareversion gefunden.
Daher habe ich die Firmware verwendet, die in einer Digi-Doku empfohlen wurde.
Ich habe API Enable in den Modem Settings gesetzt und beim kommunizieren via X-CTU muss ich natürlich dann vorne das Häkchen für API setzen.
Das funktioniert mal soweit aber halt nur via X-CTU und zumindest kommt auch auf com5 via IPS Debugfenster etwas (der zerhackte String) an.

Wart mal paar Minuten. Ich setz es mir nochmals auf.
Geb dir dann Bescheid.

gruß
bb

So, nochmal getestet, funktioniert astrein.

Übers Terminal vom XCTU (Enddevice) sende ich „1234“ an den "Coordinator welcher am IPS hängt.

Im debug window des Seriellen Port siehst pro Byte einen ganzen API Frame ankommen. Die Daten stecken im vorletzten Byte.

Im debug Window des Splitter (heist bei mir Qube) ist der Frame schon decodiert und es taucht nur noch „1234“ in Hexdarstellung auf.

Über die Registervariable und Script schreibe ich die dann ins Meldungsfenster. - Die Daten sind hier nur etwas vermantscht, damit man was sieht. Habs nur auf die schnelle hingefrickelt.

Kann hier soweit keinen Fehler entdecken, geile Sache das Xbee Zeug.

gruß
bb

thx für die Info !!! Sogar noch mit Bild :slight_smile:
Werde es auch mal direkt mit über X-CTU senden testen.

Vielleicht sieht der API Frame ja mit der Zigbee Firmware anders aus… das werde ich mal testen. (War so froh, dass ich einen Join hinbekommen hatte… aber das werd eich auch nochmal schaffen :wink:

Mein XBee möchte die XB24 802.15.4 Vers. 10E8 nicht :confused:

Getting modem type…OK
Programming modem…Flash checksum error failed
Write Parameters…Failed

Die XB24-B ZNET 2.5 war ursprünglich drauf, die kann ich auch problemlos flashen.

Die XB24-ZB funktioniert ebenfalls.

In den XB24-B und XB24-ZB kann ich aber die 16Bit MY Adresse nicht einstellen…

Keine Ahnung was ich falsch mache… ich habe zum Programieren den sparkfun Adapter von Watterott.

:frowning:

Kann es evtl. sein, das ihr hier von zwei völlig unterschiedlichen XBee Versionen sprecht?

Es gibt hier mehrere XBee Protokolle, die HW hat demzufolge auch eine andere Firmware.

Grüße,
Doc

Blöde Geschichte

keine Ahnung obs da unterschiedliche XBee Varianten gibt.
Hab 2 mal gebraucht von einem IPS USer gekauft, und dann nochmals 2 ausm Original Developers Kit.

Zum Flashen und rumprobieren verwende ich die Platine außm Developer Kit.
Kann mir aber nicht vorstellen das es daran liegt, da ist nur ein USB/UART Adapter, Stromversorgung paar LED und Taster drauf.
Kann dir ja mal den Schaltplan mailen falls es was hilft ?

In der Anwendung hab ich am Coordinator (IPS Rechner) eine Eigenbauplatine mit RS232 UART. Auch nix besonderes, alles streight-forward.

Hast mal den empfangenen Datastream mit meinem Beispiel verglichen ?
Falls der wegen anderer Firmware nicht stimmt kanns natürlich auch nicht funktionieren.

Alternativ kannst ja den Datenstrom direkt am COMport abgreifen und dann manuell zerlegen. Ist zwar aufwändiger, aber wenn sonst nix geht.

Also mit meiner Firmware kann ich alle Adressen frei einstellen.
Dann klappt auch Point-to-Point direkt über COMx ohne das IPS-Gateway-Splitter-API Gedöns. Also qausi eien simple RS232 Verlängerung.

Point-to-Multipoint geht hier am einfachsten via IPS-Gateway-Splitter da dies den API Mode benutzt und damit die Destination Adresse bei jedem Transfer flexibel geändert wird.

viel Glück
bb

Das ging auch mehr ums flashen der richtigen FW.

Gab es nicht mal die XBee pro und die v2.5?

Ist bei mir schon wieder so lange her :o

Doc

Hallo FipsJr,

du hast scheinbar ein XBee Series 2 Modul. Das ist der Nachfolger der im IPS unterstützten Module. Bedeutet: Geht alles nur von Hand. Keine IPS-Unterstützung! Dafür aber Mesh-Unterstützung!! Die gleichen habe ich auch im Einsatz: http://www.ip-symcon.de/forum/f33/xbee-series-2-betrieb-9345/

Code kannst du bei Bedarf gerne haben.

Gruß
Rubberduck

Ja, ich habe ein v2 und kein v1. Offensichtlich läuft das v2 dann nicht mit der FW der alten v1…
Es gibt ja kaum noch v1. Das ist ja doof, dass IPS nur v1 kann, sonst Handarbeit nötig ist. :loveips:

Code wäre nicht schlecht - bin was php angeht ein echter newbee/dau :wink:
Wie erkenne ich denn dann, von welchem End device der String kam?
Ich muss ja erstmal die einzelfragmente zusammensetzen bis das CRLF kommt und dann wieder in die drei Teilstrings zerlegen und in Variablen speichern. Quasi eine 3 x n Matrix :eek:

gute N8 und schonmal einen guten Rutsch!!

Gruß FipsJr

Der Code von mir zerlegt dir den Frame des Coordinator-XBee mit ZB-Firmware so weit, bis die Nutzdaten von der Gegenstelle überbleiben. Die Sache ist nämlich die: Im ZB-Netz wird die Adresse dynamisch vergeben, wenn sich das Modul beim Coordinator anmeldet. Du kannst aber jedem XBee einen Namen (Node Identifier NI) geben. IPS durchsucht für mich das Zigbee-Netz und legt eine Tabelle mit dem Zusammenhang Adresse-Name in einer String-Variable ab. Wenn eine IO sich meldet, bekomme ich die Adresse, suche den Namen dazu und weiß danach, was ich mit den Nutzdaten machen soll.

Probiers einfach mal:

<?

	include_once("XBee_Global.ips.php");


	/* Aufbau API-Frame
		Start(0x7E) - Len(MSB) - Len(LSB) - Frame-Data - Chk(1Byte)
		
		Aufbau Frame-Data
		CmdID(1Byte) - CmdData(n Bytes)
		
	*/

	$xbee_debug = True;

   //Buffer auslesen: Dateneingang ist Register Variable
   $buffer = $IPS_VALUE;
   //Daten vom letzten Empfang holen und zusammenfügen
	$old_buffer = RegVar_GetBuffer($IPS_INSTANCE);
   $buffer = $old_buffer.$buffer;

	//Alle Telegramme extrahieren wenn String lang genug und Startzeichen da
	while (substr_count($buffer,chr(0x7E)) > 0) {

	   //Startzeichen suchen und Teilstring danach bilden
	   $frame = strstr($buffer,chr(0x7E));
	   $frame = substr($frame,1);

	   //Mindestlänge für valides Frame noch nicht erreicht?
	   if (strlen($frame)<5) {
	      //Gesamtdaten wieder speichern
	      RegVar_SetBuffer($IPS_INSTANCE, $buffer);
	      return;
	   }

	   //Paketlänge extrahieren
	   $len = ord(substr($frame,0,1))*256 + ord(substr($frame,1,1));
	   //Datenframe noch nicht vollstaendig?
	   if (strlen($frame) < ($len+3)) {
	      //Gesamtdaten wieder speichern
	      RegVar_SetBuffer($IPS_INSTANCE, $buffer);
	      return;
	   }


		//Only for debug
		$debug = "";
      for ($x=0; $x < $len+3;$x++){
         $debug = $debug." ".dechex(ord(substr($frame,$x,1)));
      }
		if ($xbee_debug) IPS_LogMessage("XBee","Frame received: ".$debug);



		//Frame-Data extrahieren
		$data = substr($frame,2,$len);
		//Restbuffer ermitteln
	   $buffer = substr($frame,$len+3);




		//Checksum prüfen
		$check = ord(substr($frame,$len+2,1));
		//Checksum bilden
      for ($x=0; $x < $len;$x++){
         $check += ord(substr($data,$x,1));
      }
      //Auf Byte begrenzen
		$check = $check & 0xff;
		//Checksum NOK?
		if ($check <> 0xff) {
		   //Paket verwerfen, Rest aufheben
		   $frame = substr($frame,$len+3);
			IPS_LogMessage("XBee", "Checksum NOK Frame: ".$debug);
	      RegVar_SetBuffer($IPS_INSTANCE, $buffer);
		   return;
		}
		if ($xbee_debug) IPS_LogMessage("XBee","Checksum OK");



		//API CmdID extrahieren
		$cmd = ord(substr($data,0,1));
		$data = substr($data,1);
		$len -= 1;

		switch ($cmd) {

		   case 0x88: //AT-Response
		      $at_cmd = substr($data,1,2);
		      $status = dechex(ord(substr($data,3,1)));
		      
		      //for debug only
				$debug = "";
		      for ($x=4; $x < strlen($data);$x++){
		         $debug = $debug." ".dechex(ord(substr($data,$x,1)));
		      }
		      $data = substr($data,4);
				if ($xbee_debug) IPS_LogMessage("XBee","AT-Response CMD: ".$at_cmd." Status: ".$status." Data: ".$debug);


				//Node Discovery ?
				IF ($at_cmd == "ND") {

				   //IO_ADR bilden = 64Bit-HW-Adr & 16Bit-Node-Adr
				   $io_adr = "";
			      for ($x=2; $x < 10;$x++){
			         $io_adr .= str_pad(dechex(ord(substr($data,$x,1))),2,"0",STR_PAD_LEFT);
			      }
			      for ($x=0; $x < 2;$x++){
			         $io_adr .= str_pad(dechex(ord(substr($data,$x,1))),2,"0",STR_PAD_LEFT);
			      }

		         //Leading Space auch weglassen
					$io_name = trim(strtok(substr($data,10),chr(0)));

					if ($xbee_debug) IPS_LogMessage("XBee","Node-information received as result to Node-Discovery ADR: ".$io_adr." Name: ".$io_name);

					//node schon vorhanden, aber mir anderer Adr.?
					if (array_search($io_name,$nodes) !== false)	unset($nodes[array_search($io_name,$nodes)]);
					//Discovery-Ergebnis in Nodes-Array speichern
				   $nodes[$io_adr] = $io_name;
			   	//Array speichern
				   SetValue($node_var,serialize($nodes));
				}

				break;




		   case 0x8A: //Modem Status
				if ($xbee_debug) IPS_LogMessage("XBee","Modem Status: ".dechex(ord(substr($data,0,1))));
		      break;





		   case 0x8B: //Tx Response
		      $status = array(0=>"Success",2=> "CCA Failure",15=> "Invalid destination endpoint",21=> "Network ACK failure",
		                     22=>"Not joined to network",23=>"Self addressed",24=>"Address not found",25=>"Route not found");

				$adr = "";
				$status_str = $status[ord(substr($data,$x,4))];
		      for ($x=1; $x < 3;$x++){
		         $adr .= dechex(ord(substr($data,$x,1)));
		      }

				if ($xbee_debug)
				{
		         IPS_LogMessage("XBee","Tx response for address ".$adr.": Retries: ".ord(substr($data,$x,3))." Result: ".$status_str);
				}
				elseif ($status_str != "Success")
				{
					IPS_LogMessage("XBee","Tx response for address ".$adr.": Retries: ".ord(substr($data,$x,3))." Result: ".$status_str);
			   }
				break;





			case 0x90; //Receive Stream von IO
			   //Adresse extrahieren
			   $io_adr = "";
			   for ($x=0; $x < 10;$x++){
			         $io_adr .= str_pad(dechex(ord(substr($data,$x,1))),2,"0",STR_PAD_LEFT);
			      }
			   //Nutzdaten trennen
		      $data = substr($data,11);

		      $debug = "";
		      for ($x=0; $x < strlen($data);$x++){
		         $debug = $debug." ".dechex(ord(substr($data,$x,1)));
		      }

		      //Station ist bekannt?
		      if (array_key_exists($io_adr,$nodes)) {
			      if ($xbee_debug) IPS_LogMessage("XBee","Rx from IO# ".$nodes[$io_adr]." Data: ".$debug);

				      $daten = $data;


					//************************************************************************************************************
				   //Stationsselektiv abarbeiten
				   switch ($nodes[$io_adr])
					{
						case "HZG": //**************Hier den NI eintragen
//***************Hier wird dann das Skript zum Auswerten der Daten aufgerufen
						   IPS_RunScriptEx(14546 /*[HOCO\HOCO_D_Heizung]*/,array("data" => $daten));
						   break;
				   }
					//************************************************************************************************************

				//IO-Adresse nicht bekannt
			   }else{
			      IPS_LogMessage("XBee","Rx from unknown IO# ".$io_adr." Data: ".$debug);
			      //Discovery starten um unbekannte Adresse aufzulösen
			      IPS_RunScript(52109 /*[HOCO\XBee_Discover]*/);
				}
				break;

			case 0x95; //Node Identification Indicator (Neue Node meldet sich am Coordinator an)
				   //IO_ADR bilden = 64Bit-HW-Adr & 16Bit-Node-Adr
				   $io_adr = "";
			      for ($x=0; $x < 10;$x++){
			         $io_adr .= str_pad(dechex(ord(substr($data,$x,1))),2,"0",STR_PAD_LEFT);
			      }
		         //Leading Space auch weglassen
					$io_name = strtok(substr($data,22),chr(0));

					IPS_LogMessage("XBee","Node-information received from IO ADR: ".$io_adr." Name: ".$io_name);
					//Discovery-Ergebnis speichern
				   $nodes[$io_adr] = $io_name;
			   	//Array speichern
				   SetValue(31177 /*[HOCO\XBee_Decode\XBee_Nodes]*/,serialize($nodes));
				break;


			default:  //Dieses Cmd ist noch nicht implementiert
				$debug = "";
		      for ($x=0; $x < $len;$x++){
		         $debug = $debug." ".dechex(ord(substr($data,$x,1)));
		      }
				IPS_LogMessage("XBee","Unknown RxD Cmd: ".dechex($cmd)." Data: ".$debug."
");

		}

	}

	//Restbuffer sichern
	RegVar_SetBuffer($IPS_INSTANCE, $buffer);


?>

Dann noch der Include von oben:

<?


	function XBee_Send($data)
	{

	   global $xbee_debug;

		//Laenge bilden
		$len = strlen($data);

		//Startzeichen
		$frame = chr(0x7e);

		//Laenge
		$frame .= chr(floor($len/256)).chr($len %256);

		//Daten
		$frame .= $data;

		//Checksum
		$check = 0;
	   for ($x=0; $x < $len;$x++){
	   	$check += ord(substr($data,$x,1));
		}
		$check = $check & 0xff;
		$check = 0xff - $check;
		$frame .= chr($check);

		$len = strlen($frame);
		$debug = "";
      for ($x=0; $x < $len;$x++){
         $debug = $debug." ".dechex(ord(substr($frame,$x,1)));
      }
		if ($xbee_debug) IPS_LOGMESSAGE("XBee","Frame send: ".$debug);

//********************Hier die Register Variable zum Senden eintragen
		RegVar_Sendtext(33202 /*[XBee Serial Port\XBee Register Variable]*/,$frame);

	}


//********************Hier die String-Var zum Speichern der Node-Tabelle eintragen
	//Globale String-Variable zum Speichern der dynamischen Node-Adressen
	$node_var = 31177 /*[HOCO\XBee_Decode\XBee_Nodes]*/;


	$xbee_debug = false;

   $nodes = unserialize(GetValue($node_var));
   //Wurden Nodes rückgelesen?
   if (!is_array($nodes)) {
      //Leeres Array anlegen
      $nodes = array();
   }


?>

Sollte irgendwo ein Fehler kommen, sag mir Bescheid. Ich hab den Code nämlich etwas gekürzt, weil bei mir noch andere Funktionen enthalten sind.

Good Luck
Rubberduck

Super, vielen Dank!!! :slight_smile:
Damit mache ich direkt nächstes Jahr weiter :wink:

Guten Rutsch !!!
FipsJr

Hallo Rubberduck,

die Scripte funktionieren wunderbar.

Was ich jetzt noch als Beispiel benötige, wie kann ich ein AT-Befehl senden bzw. ein Text an irgend einen XBee.

Bis dann
Ulli

Hallo Ulli

für Xbee v1 hab ichs mal hier dokumentiert.

Vieleicht hilfts dir.

@FipsJr
Sorry, wußte nicht das du v2 hast, bzw. das die teilweise nicht kompatibel sind.

gruß
bb

hatte ich schon vorher gelesen.

Meine Frage galt der Function XBee_Send($data) im Script XBee_Global.ips.php von Rubberduck und dort der Variable $data.
Welche Daten müssen in dieser Variablen wie eingetragen werden?

Bis dann
Ulli