Dear community,
I am pretty new to the Arduino neighborhood - and a bit rusty concerning my own programming in c++. But I hope to get into gear quickly again.
Anyway, I recently got myself an Arduino Uno and a Wifi Shield 2.0 from SeeedStudio (tech details at the end of this post). Planned project is to have a webserver (its basic purpose will be to read out some pin states, lit some LEDs and primarily calculate, and show the last time stamp when certain pin states had changed).
A bit of background story:
On my way there (during the last couple of evenings), I already solved a few problems.
Just in case anyone else runs into the same problems: here they are.
I had quite some difficulties connecting to my existing Wifi network, i.e. to my Access Point (AP) via WPA2 authentication.
As a beginner, I just tried the example from http://wiki.seeedstudio.com/Wifi_Shield_V2.0/ , specifically the Example 4, since that is basically what I need as a starter.
It wouldn’t connect to my AP, and in the end turned out to be a mean combination of two factors:
a) The SSID may contain spaces (emtpy characters) like in my SSID, but in the string, you have to substitute them by escape character $.
The command to assign a different character here didn’t work, by the way. Not sure if it was my fault. Was in an early phase of learning.
b) The WPA pass phrase may not exceed 22 characters. Mine does because the encryption gets stronger with longer passwords.
Hey guys, a tiny comment in the code snippet would have saved a lot of time.
#define SSID “myssid” //spaces in the SSID have to be substituted by $ in this string
#define KEY “mypassword” //keys with more than 22 characters are not processed correctly
Anyway, this is what I finally achieved: I could get the example 4 from http://wiki.seeedstudio.com/Wifi_Shield_V2.0/ running.
Wow. What an achievement.
Now, what is my actual current problem?
What if the AP has a temporary power failure, or the connection to the AP is lost temporarily for any other reason?
I learned from forum studies that the RN-171 which is on the shield is not good in reconnecting from within loop(). The handbook does not elaborate on this at all - or I am blind…
I also learned that rebooting is not so easy, neither for the shield (does not lead to reconnection) nor for the Arduino itself (a true reboot by software that has the same effect like the hardware button is not part of the design).
Well, so I did what is (according to most forums) the cleanest way and what is as close to the HW button as one can get: I use the watchdog to initiate a “reconnect” to the AP during setup(). Or better: I plan to use it once I can figure out how the damn RN-171 let me know whether it is still connected to the AP.
To be honest: the guys having written the WiFly library… A bit more of code commenting would help a lot.
To put it short:
How can I retrieve the information “still connected to AP” while being up and ready as a webserver?
If I use
in the loop(), it leads to an immediate disconnect from the AP if it happens during a GET request from outside via HTTP. My guess is because the module receives and sends data while I try to switch into the command mode.
</s>wifly.isAssociated()<e>
Alternatively:
How can I make the Wifi Shield 2.0 automatically reconnect again once the AP is available again (after the circuit breaker for the room with the AP is in place again, for instance)?
My code (pretty much the same as in the example; just added or altered a few lines for trying to improve things) is this:
[code]#include <SoftwareSerial.h>
#include “WiFly.h”
#define SSID “Best$Place” // space characters in the SSID must be substituted in this string by $
#define KEY “thisisnotmyrealpassword” // maximum 22 characters allowed
// check your access point’s security mode, mine was WPA20-PSK
// if yours is different you’ll need to change the AUTH constant, see the file WiFly.h for avalable security codes
#define AUTH WIFLY_AUTH_WPA2_PSK
int flag = 0;
// Pins’ connection
// Arduino WiFly
// 2 <----> TX
// 3 <----> RX
SoftwareSerial wiflyUart(2, 3); // create a WiFi shield serial object
WiFly wifly(&wiflyUart); // pass the wifi siheld serial object to the WiFly class
char ip[16];
void setup()
{
wiflyUart.begin(9600); // start wifi shield uart port
Serial.begin(9600); // start the arduino serial port
Serial.println("--------- WIFLY Webserver --------");
// wait for initilization of wifly
delay(1000);
wifly.reset(); // reset the shield
delay(1000);
//set WiFly params
//added this command hoping it would improve things - didn't.
wifly.sendCommand("set wlan linkmon 30\r"); // set the local comm port to 80
delay(100);
wifly.sendCommand("set ip local 80\r"); // set the local comm port to 80
delay(100);
wifly.sendCommand("set comm remote 0\r"); // do not send a default string when a connection opens
delay(100);
wifly.sendCommand("set comm open *OPEN*\r"); // set the string that the wifi shield will output when a connection is opened
delay(100);
Serial.println("Join " SSID );
if (wifly.join(SSID, KEY, AUTH)) {
Serial.println("OK");
} else {
Serial.println("Failed");
}
delay(5000);
//changed this part a bit by replacing it with code from another example
wifly.sendCommand("get ip\r");
wiflyUart.setTimeout(500);
if(!wiflyUart.find("IP="))
{
Serial.println("can not get ip");
while(1);;
}else
{
Serial.print("IP:");
}
char c;
int index = 0;
while (wifly.receive((uint8_t *)&c, 1, 300) > 0) { // print the response from the get ip command
if(c == ':')
{
ip[index] = 0;
break;
}
ip[index++] = c;
Serial.print((char)c);
}
Serial.println();
while (wifly.receive((uint8_t *)&c, 1, 300) > 0);;
Serial.println("Web server ready");
}
void loop()
{
if(wifly.available()) // the wifi shield has data available
{
//exchanged the following part by the code from example 5;
//at that time, I didn't know I was running in the AP reconnect problem so had time to play around...
if(wiflyUart.find("*OPEN*")) // see if the data available is from an open connection by looking for the *OPEN* string
{
Serial.println("New Browser Request!");
delay(1000); // delay enough time for the browser to complete sending its HTTP request string
if(wiflyUart.find("pin=")) // look for the string "pin=" in the http request, if it's there then we want to control the LED
{
Serial.println("LED Control");
// the user wants to toggle the LEDs
int pinNumber = (wiflyUart.read()-48); // get first number i.e. if the pin 13 then the 1st number is 1
int secondNumber = (wiflyUart.read()-48);
if(secondNumber>=0 && secondNumber<=9)
{
pinNumber*=10;
pinNumber +=secondNumber; // get second number, i.e. if the pin number is 13 then the 2nd number is 3, then add to the first number
}
digitalWrite(pinNumber, !digitalRead(pinNumber)); // toggle pin
// Build pinstate string. The Arduino replies to the browser with this string.
String pinState = "Pin ";
pinState+=pinNumber;
pinState+=" is ";
if(digitalRead(pinNumber)) // check if the pin is ON or OFF
{
pinState+="ON"; // the pin is on
}
else
{
pinState+="OFF"; // the pin is off
}
// build HTTP header Content-Length string.
String contentLength="Content-Length: ";
contentLength+=pinState.length(); // the value of the length is the lenght of the string the Arduino is replying to the browser with.
// send HTTP header
wiflyUart.println("HTTP/1.1 200 OK");
wiflyUart.println("Content-Type: text/html; charset=UTF-8");
wiflyUart.println(contentLength); // length of HTML code
wiflyUart.println("Connection: close");
wiflyUart.println();
// send response
wiflyUart.print(pinState);
}
else
{
// send HTTP header
wiflyUart.println("HTTP/1.1 200 OK");
wiflyUart.println("Content-Type: text/html; charset=UTF-8");
wiflyUart.println("Content-Length: 540"); // length of HTML code
wiflyUart.println("Connection: close");
wiflyUart.println();
// send webpage's HTML code
wiflyUart.print("<html>");
wiflyUart.print("<head>");
wiflyUart.print("<title>WiFi Shield Webpage</title>");
wiflyUart.print("</head>");
wiflyUart.print("<body>");
wiflyUart.print("<h1>LED Toggle Webpage</h1>");
// In the <button> tags, the ID attribute is the value sent to the arduino via the "pin" GET parameter
wiflyUart.print("<button id=\"11\" class=\"led\">Toggle Pin 11</button> "); // button for pin 11
wiflyUart.print("<button id=\"12\" class=\"led\">Toggle Pin 12</button> "); // button for pin 12
wiflyUart.print("<button id=\"13\" class=\"led\">Toggle Pin 13</button> "); // button for pin 13
wiflyUart.print("<script src=\"http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"></script>");
wiflyUart.print("<script type=\"text/javascript\">");
wiflyUart.print("$(document).ready(function(){");
wiflyUart.print("$(\".led\").click(function(){");
wiflyUart.print("var p = $(this).attr('id');"); // get id value (i.e. pin13, pin12, or pin11)
// send HTTP GET request to the IP address with the parameter "pin" and value "p", then execute the function
// IMPORTANT: dont' forget to replace the IP address and port with YOUR shield's IP address and port
wiflyUart.print("$.get(\"http://");
wiflyUart.print(ip);
wiflyUart.print(":80/a\", {pin:p},function(data){alert(data)});");// execute get request. Upon return execute the "function" (display an alert with the "data" send back to the browser.
wiflyUart.print("});");
wiflyUart.print("});");
wiflyUart.print("</script>");
wiflyUart.print("</body>");
wiflyUart.print("</html>");
}
Serial.println("Data sent to browser");
}
}
}[/code]
And to provide the complete picture, here is some data:
[list]
Anything else of relevance? Well, please feel free to ask for details. Can’t think of any right now…