Thursday, 11 July 2013

Use the TP-Link TL-WR703N to send Arduino sensor data

Most solutions to send data through Wifi with your Arduino include an Ethernet shield or Wifi shield.

Another alternative I like a lot uses the PCB of a TP-Link router as a shield bridging Ethernet to Wifi.

I felt all these solutions were overkill and figured some decent connectivity could be acheived without any shield and although my solution it does not really provide complete TCP/IP connectivity to your Arduino, it  gives (root) access to your router console, and therefore the possibility to send data to the Internet through the command line.

Inside the TL-WR703N (with OpenWRT installed on it), you have a serial port console logged in as root. All you have to do, is hook it up to your arduino's serial port. There are however a couple of things you need to be careful about.

This post describes my approach.

Wiring and physical connection

You will find in another post how to make the connection between a TL-WR703N and a FTDI adapter. Well, if you're going to use an Arduino Pro Mini, you are going to need to swap the TP_OUT (TX) and TP_IN (RX) wires otherwise, both the Arduino Pro Mini and the TL-WR703N are going to transmit over the same wire.

Writing your code and debugging

Since the Arduino Mini Pro has only one serial port, you are left with two options:
  • The serial port, also used for programming and debugging (which I will detail below)
  • The software serial port (which I'm not going to cover here)
First things first, before connecting your programmed Pro Mini to your TP-Link, you need to make sure your code works. You need to remember that your Arduino is on a ROOT console and a command can be potentially devastating.

The right connection speed

Make sure you set the right serial port speed (115200 baud) to communicate with the TL-WR703N. e.g.:
void setup() {
This is the only speed that is going to work with the TP-Link router.

But not too fast...

My experience showed that although your serial port needs to be set at 115200 baud, you should not send your commands to the console too fast or your characters will become scrambled and it won't work.

If the command I want to pass to the router terminal is:
Instead of writing a command like
Which almost always gets scrambled along the way, I wrote a small function to slow things down:
void slowSerialPrint(char text[]) {
  for ( int i ; i < strlen(text) ; i ++ ) {
Note: you can play with the delay value if you still get corrupted characters.
This function can then be called as follows:

Buggy sprintf (and an alternative)

You will probably want to pass that 22.5 value dynamically. With the Arduino environment 0023, I found the sprintf function buggy and always returning '?'.

Jonathan McCrohan proposes the following solution on his blog:
sprintf(buf,"%f", floatvar); 
dtostrf(floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuf); 
For those of you where an example is always required, he even made a small example here.

Important tips

  • If you need debugging outputs, I recommend using a #define DEBUG_MESSAGES 1 statement or something, so you can flip of a switch and get rid of them. Although this is a good practice, I recommend always starting your output lines with a hash (#) to make sure that it will be ignored if it ever reaches your console.
  • When the router finishes booting, you get the "Please press Enter to activate this console." message. This obviously means that you need to start with a "\n" (newline) before sending your first command. Since it does not hurt to send empty lines, I always start by sending a newline.
  • Please remember that your router takes some time to boot. Mine takes about 45secs to boot (exroot and wifi). For this reason, I always leave a delay of 45sec in the setup function: "delay(45000);".
  • If your command ever gets scrambled by corruption on the serial line, you are likely to end up with an unclosed quote or double quote. The only solution I found for this was to send a CTRL+D. For this reason I would like to always send a "CTRL+D" followed by a newline before sending my command prompt is there and clean. I however have not found any solution for this so far, so please drop a comment below if you know how to do this.

You're up and running


  1. Hello,
    it's very nice idea but I think it's a bit clumsy. More clear and universal solution could be using protocol SLIP. For example with this library

    1. Hi Martin,
      Thanks for your message, I did not know the SerialIP library. This is indeed a much cleaner solution and I'll keep it in mind for my next hacks.

      In this case, even if it's a dirty hack, I chose this approach to be able to plug it on any root terminal without the need to add any package (less flash space and no need to maintain it if the router is updated).

  2. Hey I was curious about turning a router that doesn't support OpenWrt(Linksys BEFW11S4). Would that require controlling several of the ICs directly through the arduino?

    1. @StevenK I don't think your going to be able to do it if your router doesn't support at least on of the open firmwares, what its described in the post its possible cause openwrt allows access to the routers hardware
      @Mart ive played a bit with an 703n and arduino but mostly controling the arduino wireless using ser2net and a custom application to talk with the arduino over the serial port over tcp, but never needed to actually connect the arduino to the internet and your idea look pretty simple :)

  3. To send a control D - you merely need to look at the actual ascii that is being sent to the terminal with control + D.

    Control + D from my checking is the EOT signal (End of Transmission).
    It looks like if you send HEX char 0x04 you'll get an EOT on the terminal.
    Note it's intended usage too.

    1. Thanks for your help! CTRL+D is definitely a life saver to reset your terminal when your communication gets corrupted.