XBee Wifi send and receive data from web

2»

Comments

  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2015-02-04 - 08:24:30
    Well, for sending data on an internal network (or external) the XBee setup can be as simple as this: http://www.savagecircuits.com/showthread.php?662-XBee-Wi-Fi-Setup-X-CTU

    At that point the only real difference between internal and external is the port forwarding on the router.
    Chris Savage | Engineering Tech | Main Office: (916) 624-8333 | Direct to Tech Support: (888) 997-8267 | Website | Twitter | Google+
  • eagletalontimeagletalontim Posts: 1,384
    edited 2015-02-04 - 19:06:04
    I think Xbee to Xbee across networks would work fine, but my goal is to have 1 HTML / PHP web interface on a remote server and 1 Xbee at home connected to my network. The biggest thing I was trying to accomplish was a direct socket connection from PHP to the Xbee which I don't think is possible. Maybe it has something to do with the way PHP connects and waits for acceptance to connect to the socket?

    In your example, you show Xbee to Xbee. If you can get PHP to connect directly to an Xbee without a middle socket server running, please let me know how :)
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2015-02-05 - 10:20:39
    Okay, you're right. I seem to be missing your point. =) But I have actually done this from PC to XBee within the same network. I wrote a TCP client in VB.NET and used it to test communication long before I did all the other stuff. I do not recall experiencing any packet-loss with the app. The only thing that did happen was that when the TCP connection timed out, I had to "reconnect". I didn't seem to have any way to determine that the connection did timeout.

    It would be easy enough to test for packet-loss by writing a program that sends serialized packets and receives an acknowledgement from the remote side. This would be similar to how the one project worked sending packets over the internet, except with a PC on the other end.
    Chris Savage | Engineering Tech | Main Office: (916) 624-8333 | Direct to Tech Support: (888) 997-8267 | Website | Twitter | Google+
  • eagletalontimeagletalontim Posts: 1,384
    edited 2015-02-05 - 16:39:48
    What do you mean my "serialized" packets? I am checking for a beginning character and and end character which works, but the middle characters sometimes come through incorrectly. Like "R:C:3:#" may send fine 10 times in a row, then it will come through as "R:
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2015-02-06 - 10:36:05
    When I am testing any kind of radio system for errors or missing packets I send out two or three sets of values all combined into a packet and using a simple checksum. The first value is a serial number which starts at 0 and continues incrementing by one for each packet sent. Each time the receiver gets a valid packet it stores the serial number and when the next valid packet comes in it is checked to see if it the next value. If not it calculates how many packets were missed and adds that the the missed packet count. This way I can tell exactly how many packets have been missed over a period of time. The checksum is a simple byte, word or long (depending on what your MCU stores) that is the sum of all the bytes being sent. This value is then added to the end of the packet. I also prefix all packets with a preamble character string. For example, my current project with XBee Wi-Fi prefixes each command with, "!XB" and the next character is the command. You can always generate a checksum and compare it on the receiving end to tell you if the command has been corrupted.
    Chris Savage | Engineering Tech | Main Office: (916) 624-8333 | Direct to Tech Support: (888) 997-8267 | Website | Twitter | Google+
  • eagletalontimeagletalontim Posts: 1,384
    edited 2015-02-06 - 19:32:36
    So what do you do in the case of missing packets? This seems to be quite a difficult task to send and receive data via a socket. Watching the output of my socket server, the problem seems to be at the Xbee to the Prop.

    When I send data to the socket server, the data appears correctly in the "output view" of what the socket is getting. What is received on the XBee to the Prop is right about 80% of the time. The data sent out of the Xbee to the socket server is correct about 30% of the time.

    Data being sent from the circuit to the socket server is done via a line like : xb.str(string("Moving to Park Position", 13)) The "output view" of the socket server shows this string a number of ways and 70% of the time, it is only part of the string.
  • eagletalontimeagletalontim Posts: 1,384
    edited 2015-02-07 - 08:51:29
    i am still battling with this and getting no where :(

    SERVER.PHP output. Comments are in "( )".
    <PING>  (XBEE OUTPUT : GOOD)
    New client connected: 50.87.182.130
    <R:C:2:#>  (BROWSER OUTPUT : GOOD)
    <e:0#w:1>  (XBEE OUTPUT : GOOD)
    client disconnected.
    New client connected: 50.87.182.130
    <R:C:5:#>  (BROWSER OUTPUT : GOOD)
    More : <e0#w:0#u:0#d:0client disconnected.   (XBEE OUTPUT : FAILED)
    New client connected: 50.87.182.130
    <R:C:5:#>  (BROWSER OUTPUT : GOOD)
    <e0#w:0#u:0#d:0<:0#w:0#u:0#d:0>   (XBEE OUTPUT : FAILED)
    client disconnected.
    New client connected: 50.87.182.130
    <R:C:5:#>  (BROWSER OUTPUT : GOOD)
    More : <e:0#w0#u:0#d:0client disconnected.   (XBEE OUTPUT : FAILED)
    New client connected: 50.87.182.130
    <R:C:6:#>  (BROWSER OUTPUT : GOOD)
    <e:0#w0#u:0#d:0<esff:ffeswitchving:0>   (XBEE OUTPUT : FAILED)
    client disconnected.
    New client connected: 50.87.182.130
    <R:C:5:#>  (BROWSER OUTPUT : GOOD)
    More : <e:client disconnected.   (XBEE OUTPUT : FAILED)
    

    As you can see, the HTML / Jquery / PHP code sends fine. As soon as I try to send from the Prop to the server, the string is all messed up and half missing....

    I am using this to send through the XB :
    CON
      END_CHR = ">"
      BEGIN_CHR = "<"
    
    OBJ
       xb            : "FullDuplexSerial"   ' un modified version.
    
    PUB HandleWifi
     ........
            xb.str(string(BEGIN_CHR, 13))
            xb.str(string("e:0#w:0#u:0#d:0", 13))
            xb.str(string(END_CHR, 13))
    

    SERVER.PHP content
    <?php
    set_time_limit(0);
    
    $address = 'MY_SERVER_IP';
    $port = 2616;
    
    
    echo "Creating socket.\n";
    $sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Could not create socket.");
    
    @socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
    
    $timeout = array('sec'=>1,'usec'=>500000);
    @socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,$timeout);
    
    //socket_set_nonblock($sock);
    
    echo "Binding to socket.\n";
    $result = @socket_bind($sock, 0, $port) or die("Could not Bind to socket");
    echo "Listening....\n";
    $result = @socket_listen($sock) or die("Could not listen to socket.");
    
    $clients = array($sock);
    $string = array();
    
    while (true) {
    	$read = $clients;
    
    	if (@socket_select($read, $write = NULL, $except = NULL, 0) < 1)
    		continue;
    
    	if (in_array($sock, $read)) {
    		$clients[] = $newsock = @socket_accept($sock);
    
    		@socket_write($newsock, "Connected:");
    
    		@socket_getpeername($newsock, $ip);
    		echo "New client connected: {$ip}\n";
    
    		$key = array_search($sock, $read);
    		unset($read[$key]);
    	}
    
    	foreach ($read as $read_sock) {
    		$key = array_search($read_sock, $clients);
    
    		$data = @socket_read($read_sock, 1024, PHP_BINARY_READ);
    
    		// check if the client is disconnected
    		if ($data == false) {
    			// remove client for $clients array
    			unset($clients[$key]);
    			echo "client disconnected.\n";
    			continue;
    		}
    
    		if (!empty($data)) {
    			// REMOVE ALL NON-PRINTABLE CHARACTERS
    			$string[$key] .= preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $data);
    			
    			// IF BEGINNING CHARACTER AND END CHARACTER EXIST, OUTPUT TO ALL OTHER CLIENTS
    			if(strpos($string[$key], "<") !== false && strpos($string[$key], ">") !== false){
    				foreach ($clients as $send_sock) {
    					if ($send_sock == $sock || $send_sock == $read_sock)
    						continue;
    					@socket_write($send_sock, $string[$key].chr(13)."\n");
    				}
    				echo $string[$key]."\n";
    				unset($string[$key]);
    			} else {
    				// IF START AND END CHARACTERS DO NOT EXIST, OUTPUT EXISTING DATA TO SCREEN
    				echo "More : ".$string[$key];
    			}
    		}
    	}
    }
    @socket_close($sock);
    ?>
    
  • eagletalontimeagletalontim Posts: 1,384
    edited 2015-02-07 - 19:51:56
    So, after hours of trying to get this to work, I think I got it!

    So to collaborate on what works and what does not work...

    What does NOT work....
    PHP socket connecting directly to an XBee. Apparently the protocol is different? No matter what I tried (TCP and UDP), the connection could not be made. Maybe there is a way, but I cannot figure it out.

    TCP socket server using socket_read() as PHP_NORMAL_READ. Even with proper escapes "\r" and/or "\n", data will be lost. Not sure what causes this.

    TCP socket client using socket_read() as PHP_BINARY_READ to read from the socket causes the server script to hang or timeout since it is trying to "stream" the data. Checking for a "start" and "end" character may help but decided to use PHP_NORMAL_READ and end each string with chr(10) and chr(13)

    What does work...
    Communicating with an XBee in Transparent Mode via PHP TCP socket server!

    Streaming output of Xbee to socket server without "\r" and "\n" : string("blah", 13). Use "start" and "end" characters to parse on socket server script to output to other clients (Thank you Chris for this idea). Socket Client will receive what the server parses and adds the "\r\n" to.

    In my case, I used "<" and ">" symbols as Chris did in his project. The client (HTML Form) would send a string such as <R:C:5:#> to the socket server. The server script would check for both start and end symbols and if there, grab the string between the delimiters and send to other connected clients. The Xbee will read this data and check for an "R" for the beginning character and an # symbol before processing the string to get the command.

    In order to keep the Xbee connected to the server, I set TM (TCP Client Connection Timeout) to the value 1770 which is 6000 * 100ms or 600 seconds. When the program starts, it sends a string to the socket server which accepts the connection and creates the client. In the PROP code, the Xbee will "PING" the server every 20 seconds to keep the connection alive.

    Now for the code!

    socket.php - creates multiclient socket server. Cron runs this script every minute using nohup php socket.php
    <?php
    set_time_limit(0);
    
    function extract_unit($string, $start, $end){
    	$pos = stripos($string, $start);
    	$str = substr($string, $pos);
    	$str_two = substr($str, strlen($start));
    	$second_pos = stripos($str_two, $end);
    	$str_three = substr($str_two, 0, $second_pos);
    	$unit = trim($str_three); // remove whitespaces
    	return $unit;
    }
    
    $address = 'SERVER_IP_ADDRESS';
    $port = SERVER_PORT;
    
    
    echo "Creating socket.\n";
    $sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Could not create socket.");
    @socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
    $timeout = array('sec'=>2,'usec'=>500000);
    @socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,$timeout);
    echo "Binding to socket.\n";
    $result = @socket_bind($sock, 0, $port) or die("Could not Bind to socket");
    echo "Listening....\n";
    $result = @socket_listen($sock) or die("Could not listen to socket.");
    $clients = array($sock);
    $string = array();
    
    while (true) {
    	$read = $clients;
    	if (@socket_select($read, $write = NULL, $except = NULL, 0) < 1)
    		continue;
    	if (in_array($sock, $read)) {
    		$clients[] = $newsock = @socket_accept($sock);
    		@socket_write($newsock, "Connected:");
    		@socket_getpeername($newsock, $ip);
    		echo "New client connected: {$ip}\n";
    		$key = array_search($sock, $read);
    		unset($read[$key]);
    	}
    
    	foreach ($read as $read_sock) {
    		$key = array_search($read_sock, $clients);
    		$data = @socket_read($read_sock, 512, PHP_BINARY_READ);
    		// check if the client is disconnected
    		if ($data == false) {
    			// remove client for $clients array
    			unset($clients[$key]);
    			echo "client disconnected.\n";
    			continue;
    		}
    
    		if (!empty($data)) {
    			// REMOVE ALL NON-PRINTABLE CHARACTERS
    			$string[$key] = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $data);
    
    			// IF BEGINNING CHARACTER AND END CHARACTER EXIST, OUTPUT TO ALL OTHER CLIENTS
    			if(strpos($string[$key], "<") !== false && strpos($string[$key], ">") !== false){
    				$tosend = extract_unit($string[$key], "<", ">");
    				foreach ($clients as $send_sock) {
    					if ($send_sock == $sock || $send_sock == $read_sock)
    						continue;
    					@socket_write($send_sock, $tosend.chr(10).chr(13));
    				}
    				echo $tosend."\n";
    				unset($string[$key]);
    			} else {
    				// IF START AND END CHARACTERS DO NOT EXIST, OUTPUT EXISTING DATA TO SCREEN
    				echo "More : ".$string[$key];
    			}
    		}
    	}
    }
    @socket_close($sock);
    ?>
    

    client.php - Sends data from HTML form and returns data sent back from PROP
    <?
    function after($this, $inthat){
    	if (!is_bool(strpos($inthat, $this)))
    	return substr($inthat, strpos($inthat,$this)+strlen($this));
    }
    
    $do = $_REQUEST['do'];
    $text = $_REQUEST['text_message'];
    
    $port = SERVER_PORT;
    $address = 'SERVER_IP_ADDRESS';
    
    if($do == "sendmessage"){
    	$socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    	if ($socket === false) {
    		echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
    		die();
    	}
    	$timeout = array('sec'=>2,'usec'=>500000);
    	@socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,$timeout);
    	$result = @socket_connect($socket, $address, $port);
    
    	@socket_write($socket, $text, strlen($text));
    
    	$str = '';
    	$str = @socket_read($socket, 512, PHP_NORMAL_READ);
    	@socket_close($socket);
    
    	$str = after("Connected:", $str);
    	$data_array = explode("#", $str);
    	$string = '';
    	if(is_array($data_array) && isset($data_array[1])){
    		foreach($data_array as $data){
    			$value = explode(":", $data);
    			$string .= $value[0]." = ".$value[1]."</br>\n";
    		}
    		echo $string;
    	} else {
    		echo $str;
    	}
    } else {
    	echo "empty";
    }
    ?>
    

    control_panel.html - Web interface. Yes, I used Tables :P Was in a hurry. Images were just clipart found on Google. Also well visible on a smart phone or tablet.
    <!DOCTYPE html>
    <html>
    <head>
    	<title>Project Controller</title>
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.js"></script>;
    	<script language="JavaScript">
    	function submit_text(what){
    		formid = document.getElementById("form_1");
    		$.post(
    			"client.php",
    			{
    			do: "sendmessage",
    			text_message: what
    			},
    			function(data) {
    				$('#text_body').html(data);
    				data = '';
    			}
    		);
    	}
    	</script>
    	<style>
    		body{
    			font-size:3em;
    		}
    
    		table td{
    			padding:20px;
    			height:100px;
    		}
    	</style>
    </head>
    <body>
    
    	<div class="form_body" id="form_body">
    		<div class="post_message">
    			<table width="100%" cellpadding="0px" cellspacing="0px" style="border:1px solid;">
    				<tr>
    					<td style="text-align:left;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:9:#>');"><img src="images/park.jpg" height="100px" border="0"></a>
    					</td>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:3:#>');"><img src="images/arrow-up.jpg" height="100px" border="0"></a>
    					</td>
    					<td>&nbsp;</td>
    				</tr>
    				<tr>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:1:#>');"><img src="images/arrow-left.jpg" height="100px" border="0"></a>
    					</td>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:5:#>');"><img src="images/stop-sign.jpg" height="100px" border="0"></a>
    					</td>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:2:#>');"><img src="images/arrow-right.jpg" height="100px" border="0"></a>
    					</td>
    				</tr>
    				<tr>
    					<td>&nbsp;</td>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:4:#>');"><img src="images/arrow-down.jpg" height="100px" border="0"></a>
    					</td>
    					<td>&nbsp;</td>
    				</tr>
    				<tr>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:7:#>');"><img src="images/lock.jpg" height="100px" border="0"></a>
    					</td>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:8:#>');"><img src="images/unlock.jpg" height="100px" border="0"></a>
    					</td>
    					<td style="text-align:center;">
    						<a href="javascript:void(0);" onClick="submit_text('<R:C:6:#>');"><img src="images/info.jpg" height="100px" border="0"></a>
    					</td>
    				</tr>
    			</table>
    		</div>
    		<div style="clear:both;"></div>
    	</div>
    	<div class="text_body" id="text_body" style="width:100%">
    
    	</div>
    </body>
    </html>
    

    myproject.spin - The XBee part of my project. I am just going to attach this. You can strip out whatever you don't need :)

    Thanks for the help / suggestions!
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2015-02-09 - 08:59:56
    Glad to hear you got it working. I'm not much for PHP. I have modded my website heavily (which uses PHP), but only within the realm of what is already capable on the various pages.
    Chris Savage | Engineering Tech | Main Office: (916) 624-8333 | Direct to Tech Support: (888) 997-8267 | Website | Twitter | Google+
  • eagletalontimeagletalontim Posts: 1,384
    edited 2015-02-09 - 17:34:16
    Yes, I am quite happy to get it working reliably. I am continually changing the script to add more functions / redo some of the functions so I can use this thread as a "restart" point if needed. PHP is my strong point and SPIN is like a 6th language for me so I am still attempting to learn it while keeping up to date in all the other languages I know.... Pretty tough!
  • Since the url http://www.savagecircuits.com/showthread.php?662-XBee-Wi-Fi-Setup-X-CTU is no longer available,

    is it possible to have a example of a program in spin that just :
    - configure the xbee S6B
    - send a http get request to http://www.google.com
    - print the output to the serial.

    i would like to retrieve information from the weather channel but i don't know how to start
  • I am not sure about getting the Xbee communicating directly with the web and requesting the output of a page. The Xbee setup I have is connecting to a port that I have a PHP socket server running on. The Xbee can send out a "Ping" command and request data every X seconds and the socket server will process the data and send back whatever information you want.

    To parse weather data, you will have to find an XML feed which will be the easiest to work with to parse using the PHP socket server. Have the socket server wait for the command from the Xbee, when the command comes, pull the data from the website or XML file, parse the data, and send back the response to the XBee to use in your SPIN program. If you need help with the PHP socket server or the spin, let me know :)
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    laurent974 wrote: »

    Apologies for that. When my wife passed away I kind of lost motivation to fix the site issues caused by vBulletin. I have new software and eventually I will have the content back up. I appreciate your patience.

    Chris Savage | Engineering Tech | Main Office: (916) 624-8333 | Direct to Tech Support: (888) 997-8267 | Website | Twitter | Google+
  • Chris, I have created scripts that can export the Vbulletin scripts to other scripts if you need help with that. Sorry to hear about your wife! Hope you are doing well.
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    I have stopped using vBulletin and am now just running a Joomla site at the same address. I just need to take some time to get the content back up. I backed everything up from my old website.
    Chris Savage | Engineering Tech | Main Office: (916) 624-8333 | Direct to Tech Support: (888) 997-8267 | Website | Twitter | Google+
  • laurent974laurent974 Posts: 67
    edited 2016-04-08 - 20:27:52
    Thank you very much Chris. I'll wait for your help.

    I'm sorry too for your wife. I hope you have taken confort with your familly or your friends.

    [Edit] after 2 days hitting a wall, i found at last how to send a http get request from the xctu console.
    i 'spend the whole day lurking every forum until i found that comment here
    http://www.digi.com/support/forum/34364/xbee-is-not-receiving-tcp-data?show=34368#a34368
    I've got "GET HTTP" to work . My issue was that I did not supply the complete escape sequence for the GET HTTP string which is "\r\n\r\n" or 0d, 0a,0d,0a. so the total request in the API frame payload is "GET / HTTP/1.1\r\n\r\n". Hope this helps someone. Took me quite a few hours to nail it.

    now i still have to code in spin to send that from propeller.
Sign In or Register to comment.