Imprimer
Catégorie : Embedded Systems
Affichages : 114


Preamble


Classical arduino development board (Uno, genuino, ...) do not host a wifi chipset. A wifi "shield" (i.e. an additional board that plugs on the pins of the arduino board) must be used for that. Nevertheless, there are other micro-controllers that are already capable of communicating over wifi, bluetooth, ... for example esp32 and their "little brother", the esp8266.

Thanks to the arduino development kit for these micro-controllers, it is very easy to setup a wifi connection and to communicate with a web server, or a classical one directly over TCP. The goal of the following exercises is to discover how.

BEWARE ! these boards may be fragile, so do not touch the surface component, at risk to burn the card

  

Setup

 

 
Exercise #1: connect to Wifi AP + send TCP request
 

Working principles:

  • During setup, the esp8266 connects to the wifi access point, then to the server written in Java.
  • During loop, the esp8266 must regularly read on pin A0 (connected to the piezo), and if the value is greater than 500 :
    • sends a request to the server to report the value read
    • reads the server answer and print it on Serial
    • waits for 500ms.
  • If the value is lower than 500, the µC does nothing and just finishes loop().

 

What must be done:

  • create a new sketch.
  • add function to read a line from the server (e.g. readLine() in the course article)
  • add functions to establish a connection to the Wifi access point and the TCP server, as seen in the course. For that, use
    • AP credentials : ssid = testingiot, password = testingiot
    • TCP serveur : ip = 192.168.0.2, port = 12345. IMPORTANT : as soon as the connection is established, the server sends a line containing the id of the client.
  • add a function to send a request for the piezo to the server:
    • the format of the request is : PIEZO id_client piezo_value, where id_client must be replaced by the value received from the server after connection, and piezo_value by the values read on A0.
  • NB : the answer to the request fits on one or two lines :
    • the first one contains OK if the request is valid, or ERR message if invalid.
    • the second one occurs only if the first one is OK. It contains the voltage on A0, computed from the value read (e.g. if read = 1023, the answer should be 3.3, but if read = 1024, it is considered as an overload, so an invalid value is reported from the server)
  • In loop() (apart connecting to the server) :
    • read a value on A0
    • if value >= 500 :
      • call the function described above,
      • wait for the answer (in one or two lines, see above)
      • print the result (error/voltage),
      • wait for 500ms.
    • if not, wait for 3ms.
  • RECALL : because of hardware limitations of the ESP8266, it is not possible to read on A0 as fast as possible. There must be at least 3ms between two readings, hence the delay of 3ms mentioned above.
 
Exercise #2: connect to Wifi AP + send TCP request + interrupt
 

Working principles:

  • During setup, the esp8266 connects to the wifi access point, then to the server written in Java.
  • During loop, the esp8266 uses an interrupt to catch the changes of the button. At every change, the µC :
    • sends a request to the server to report the value read
    • reads the server answer and print it on Serial

 

  • The main challenge of this exercise is that it is not possible to write an interrupt function that sends a request to a server. Indeed, that function MUST NOT do some processing with an unknown execution time, which is exactly the case of a request to a server.
  • The single viable solution is to use a boolean variable that signals that a request must be sent.

 

What must be done :

  • create a new sketch by copying that of exercise 1.
  • add a boolean variable (e.g. mustSendRequest)
  • add an interrupt function that :
    • reads the state of the button,
    • if state = 1, light on the LED and if state = 0, ligth it off
    • set mustSendRequest to true.
  • NB : dont' forget to call attachInterrupt() in setup() to bind the D2 pin changes to the interrupt function.
  • add function to read a line from the server (e.g. readLine() in the course article)
  • add functions to establish a connection to the Wifi access point and the TCP server, as seen in the course. For that, use
    • AP credentials : ssid = testingiot, password = testingiot
    • TCP serveur : ip = 192.168.0.2, port = 12345. IMPORTANT : as soon as the connection is established, the server sends a line containing the id of the client.
  • add a function to send a request for the button to the server and to wait for the answer :
    • the format of the request is : BUTTON id_client button_state, where id_client must be replaced by the value received from the server after connection, and button_state by the value read on D2 (= button), i.e. 0 or 1.
  • NB : the answer fits on one line: OK if the request is valid, or ERR message if invalid.
  • In loop() (apart connecting to the server) :
    • If mustSendRequest is true, call the above function, read+print the answer, and reset mustSendRequest to false
 
Exercise #3: connect to Wifi AP + send TCP request + interrupt (bis)
 

Working principles:

  • During setup, the esp8266 connects to the wifi access point, then to the server written in Java.
  • During loop, the esp8266 uses an interrupt to catch the changes of the button using an interrupt function.
  • The goal is to send a request to the server only after the button is released.

 

What must be done :

  • create a new sketch, copying that of exercise 2.
  • Modify the interrupt function so that :
    • it saves the current time (recall: use millis() ) when the button is pressed and released (so 2 variables are needed)
    • Only if released set mustSendRequest to true.
  • Modify the request function so that :
    • the format of the request is : PRESS id_client time_pressed time_released, where id_client must be replaced by the value received from the server after connection, and the two other parameters by the values stores by the interrupt function.
  • NB : the answer fits on one or two lines :
    • the first one contains OK if the request is valid, or ERR message if invalid.
    • the second one occurs only if the first one is OK. It contains the gap in seconds between the two times.
  • Modify loop() to read+print the answer to the request.

 

Exercise #4: all together
 

Working principles:

  • During setup, the esp8266 connects to the wifi access point, then to the server written in Java.
  • During loop, the esp8266 :
    • uses an interrupt to catch the changes of the button using an interrupt function.
    • read pin A0 to get the piezo level and store it in a variable only if it is >= 500 AND if there is not a value that was previously stored during the last 300ms.
    • send a request to the server when the button is pressed or released.
    • send a request every two seconds to send the current stored value of the piezo level.

The challenge of this exercise is to manage some delays before taking actions. Indeed, it is not possible to use the delay() function because it prevents to send requests at the correct moment. Two problematic cases :

  • The user tap for the first time the piezo hard enough to get value >= 500. The value is stored. If a delay is used to wait for 300ms, and if the user pushes the button while in delay, the µC must wait the end of the delay to check that mustSendRequest = true, and thus, to send a request. In the previous exercises, the request is sent as soon as possible, because there is no delay in loop(), and it should be the same here.
  • Same case, but this time, the last request to send piezo level was 1.90 seconds ago. If a delay of 300ms is used, the µC must wait the end of the delay to send another request. Thus, it will occur after 2.2 seconds, which does not comply with the contraints.

The conclusion is that for this exercise, it is not possible to use delay() function within loop() (except for the mandatory 3ms to read correctly A0). But in this case, how can I wait for 500ms, or 2 sec ?

The solution is quite simple : using millis() to "count" the elapsed time since a given moment in time. For example, to do something every 5 seconds :

setup() {
   ...
   long t = millis();
}
loop() {
   if ( (millis()-t1) >= 5000) {
      // do something
      t1 = millis();
   }
   ...
}

 

In order to fit the constraints of the exercise, two time counters are needed :

  • to count 2 seconds and, if reached, send a request with the piezo level
  • to count 300ms from the moment a new piezo level is stored, so that no other level can be stored during these 300ms.

 

Exercise #5: connect to Wifi AP + send HTTP request + interrupt
 

Working principles: identical to exercise 3, except that the request function sends a HTTP request, that is processed by a tiny web server that runs on the same

 

What must be done :

  • create a new sketch, copying that of exercise 3
  • remove code that is related to the TCP connection to the server.
  • dig into the examples of esp8266 SDK related to create a http client
  • take these examples as a source to modify the request fonction to send a GET request with a URL like : http://192.168.0.2/get_gap.php?press=xxxx&release=yyyy
  • xxxx & yyyy are the time values stored by the interrupt function.
  • This time, the request function also waits for the answer, which is a line of text, and prints it.
  • NB : the answer is a single line, containing either ERR error_message or OK - gap = xxx