1°/ Preambule

  • esp8266 and esp32 have native wifi support, which is not the case of ATmega328
  • An esp8266/esp32 can be used as a wifi client, a wifi access point, or both.
  • A client just connects to an access point and receives an IP address.
  • If a µC is used has an access point, it provides wifi connections and IP addresses (like a DHCP server), but it has not itself an IP address.
  • Nevertheless, a µC can be an access point AND a client at a time.

 

  • Whatever the case, a sketch replying on Wifi must include an header file that contains the wifi function declarations:
    • for arduino/esp32 board, it is WiFi.h,
    • for esp8266 boards, it is ESP8266WiFi.h
  • WARNING : most of the Wifi functions are identical and behave the same. Nevertheless, some are available only for the esp32 and not for the esp8266, and some other have different names and/or parameters.


2°/ µC as a Wifi client

  • The "common way" is to create a function that is called in setup().
  • this function tries endlessly to establish the Wifi connection.

Exemple :

#include <ESP8266WiFi.h>
// uncomment next line and comment the previous if using an esp32
//#include <WiFi.h>
...
void setupWifi() {
     
  const char *ssid = "ssid_wifi_ap"; // the ssid of the AP        
  const char *password = "pass_ap"; // the password of the AP  
  
  WiFi.setAutoConnect(false);  // see remark 1
  WiFi.setSleepMode(WIFI_NONE_SLEEP); // always active => big consumption, see remark 2

  WiFi.mode (WIFI_STA); // setup as a wifi client
  WiFi.begin(ssid,password); // try to connect
  while (WiFi.status() != WL_CONNECTED) { // check connection
    delay(500); 
    Serial.print(".");
  } 
  // debug messages
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
}

 

Remark 1 : 

  • setAutoConnect() is used to prevent the µC to automatically establish a connection with the last know AP (its credentials are kept in a kind of flash memory).
  • By default, this automatic connection occurs just after the boot sequence, and it may prevent the µC to connect to the ssid given in the code if it differs from the last one used.
  • This is why it is a good idea to disable this automatic connection, unless you are sure that your µC will always connect to the same ssid.

 

Remark 2 : 

  • setSleepMode() is used to set the Wifi circuit of the µC into the "sleeping" mode given in parameter.
  • The default mode is set to "modem sleep", which corresponds to cyclically power off the circuit for a small amount of time (e.g. 1 sec) and then to wake it up to check if there are some data to send receive.
  • This mode is useful to greatly extend battery life but may lead to miss some data.
  • For critical applications where a loss of data is not admitted, it is possible to let the wifi circuit always on (parameter = WIFI_NONE_SLEEP), which consume a lot of battery power.
  • There is a third possible value for the parameter: WIFI_LIGHT_SLEEP. In this mode, the program must explicitly go out of the sleep, either by configuring a time to sleep, or by awakening with an external signal. It is quite similar to the deep sleep except that the µC processor is just in pause, and thus data in RAM are not lost when it awakes.

 

3°/ µC as a Wifi access point+client

  •  Since the AP will act as a DHCP server, we must set variables to configure the network address, the network mask, ...
  • In the following example, we assume that the AP will provide addresses like 192.168.0.XXX
  • We also must choose a wifi channel for the Wifi network.
  • Note that the Wifi norm defines 13 channels that correspond to 13 frequencies around 2.4GHz. The problem is that 2 wifi networks cannot use channels that are too close unless it produces a lot of interference, and thus a lot of packet loss. The least gap is 4.
  • An esp8266/esp32 is not really powerful, so the maximum number of clients is 4 by default. Moreover, if it is itself a client, it has in charge the AP + its own code, it may rapidly crashes if it is overloaded. So, for a reliable solution, it is better to use a dedicated AP. But if we just want to communicate between 2 µC, it is sufficient and simple.

Exemple:

#include <ESP8266WiFi.h>
// uncomment next line and comment the previous if using an esp32
//#include <WiFi.h>
...
void setupAP() {
  IPAddress local_IP(192,168,0,1);
  IPAddress gateway(192,168,0,1);
  IPAddress subnet(255,255,255,0);

  WiFi.mode(WIFI_AP_STA); // AP + client
  int channel = 1; // choose between 1 and 13
  const char *ssid = "ssid_wifi_ap";        
  const char *password = "pass_ap";  

 // CAUTION: sometimes, 2 following lines may be exchanged to get it work
  WiFi.softAP(ssid, password, channel); 
  WiFi.softAPConfig(local_IP, gateway, subnet);

  // debug messages
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
}

 

4°/ TCP connection & communication

  • Once a Wifi connection is established and the µC has an IP address, it is possible to create a TCP connection.
  • A µC can act as a TCP client, or a TCP server.
  • When the TCP connection is established, we can communicate by sending/receiving bytes.

 

4.1°/ µC as a TCP Client

  • Once again, we use a dedicated function to establish the connection with the server. This function tries to initialize an instance of WiFiClient class, using the connect() method. Note that it is a good idea to use a variable that store the state of this connection. 
  • After connection is established, we can use print() to send lines of text, but unfortunately, there is no native method to read lines, only read() that reads one byte.
  • The examples below shows a (bit imperfect) workaround to get a line of text.

Exemple:

#include <ESP8266WiFi.h>
// uncomment next line and comment the previous if using an esp32
//#include <WiFi.h>
...
WiFiClient client;
byte connState;
const char* ipServ = "192.168.0.1";
int portServ = 12345;
byte buf[1024];
int idx = 0;
...

// PB : no available function to directly read a line
// so must write one, e.g. that below, which blocks
// until an end of line \n (or end of buffer) is reached
String readLine() {
  char buffer[1024]; // 1024 = max line length.
  memset(buffer,0,1024);    // reset buffer
  int index = 0; 
  char c;  
  while(true) {
    while (!client.available()) {} // wait for smthg to read
    while ((index < 1023) && (client.available())) {
      c = client.read();
      if (c == '\n') return String(buffer); // end-of-line reached => return
      buffer[index++] = c; // store the char
    }
    // prevent buffer overflow: return the whole buffer even if no \n encountered
    if (index == 1023) return String(buffer); 
  }  
}

void setup() {
  Serial.begin(115200);
  connState = 0;
  // establish the wifi connection
  ...
}

bool doConnection() {
  if (client.connect(ipServ, portServ)) {
    connState = 1;
    Serial.println("connected to server")
    // special for esp8266: disable buffering small mesg
    client.setNoDelay(true);
    return true;
  }
  else {
    connState = 0;
    Serial.println("connection failed")
    return false;
}

void loop() {
  if (connState == 0) {
    if (! doConnection()) { delay(1000); }
  }
  if (connState == 1) {
    client.write(10); // write a byte equal to 10
    client.println("10"); // write 3 bytes: ascii code of 1, ascii code of 0, ascii code of new_line
    // wait something from the server
    String msg = readLine();
    Serial.println(msg);
  }
}

 

Comments :

  • reading from a WiFiClient is tedious because there is only one function : read(), that reads just a byte. Moreover, it is not blocking (which is not the case for classical processors with an OS like unix)
  • Nevertheless, it is possible to obtain a blocking reception using : while(!client.available()) {}. On a µC, it works perfectly while on a classical processor, it is forbidden because it loads it at 100%.

 

4.2°/ µC as a TCP server

  • In some application, the µC must act itself as a server.
  • Nevertheless, it has very limited capacities, and cannot serve multiple client concurrently, as in a multithreaded server written in Java.

Exemple:

#include <ESP8266WiFi.h>
// uncomment next line and comment the previous if using an esp32
//#include <WiFi.h>
...
WiFiServer server(12345); // create the connecting socket, associated to port 12345
WiFiClient client; 
byte connState;
byte buf[1024];
int idx = 0;
...

void setup() {
  Serial.begin(115200);
  connState = 0;
  // establish the wifi connection
  ...
}

void waitConnection() {
  client = server.available(); // test if there is an incoming connection and if yes, accept it.
  if (client) {
    connState = 1;
    Serial.println("client connected")
    // special for esp8266: disable buffering small mesg
    client.setNoDelay(true);
  }
}

void loop() {
  if (connState == 0) {
    waitConnection();
  }
  if (connState == 1) {
    // wait something from the client
    while (!client.available()) {}
    // read what is available
    while (client.available()) {
      buf[idx++] = client.read(); // read & store a byte
    }
    Serial.println(String(buf)); // print the content of buf as a string
    for(int i=0;i<idx;i++) buf[i] = 0; // reset buf
  }
}

 

 

5°/ Other protocols

  • The esp8266/32 aloows to create applications using communication protocols different from TCP.
  • For example, it is possible to send/receive datagram packets, using UDP protocol,
  • It is also possible to encrypt the communications, using SSL protocol.
  • Finally, the µC can act as a HTTP Client or even as a Web Server.

 

  • There are many examples of these possibilities within the installation directory of the esp8266/32 SDK. Generally, they can be found in something like :
    • C:\Users\<username>\AppData\Local\Arduino15\packages\esp8266\hardware/esp8266\<version>\libraries under windows
    • ~/.arduino15/packages/esp8266/hardware/esp8266/<version>/libraries under linux