Part 3: More Data Exchange, Security, and the Frontend
Let me begin with a brief recap of the previous articles in this series. In Part 1 (“Handling HTTP Requests in PHP,” Circuit Cellar 399, October 2023) [1], I discussed the concepts of full-stack web development, backend/frontend web development, and basic backend workflow with MCU-based web clients. In Part 2 (“Querying a Database in PHP,” Circuit Cellar 400, November 2023) [2], I discussed setting up a database on a web server for storing sensor data from the ESP8266-based data logger, and basic Structured Query Language (SQL) queries for storing/retrieving data to/from the database. I discussed, as well, a PHP script to retrieve data from the database and convert them to the Comma Separated Value (CSV) data exchange format. After the conversion the CSV file is sent to the requesting web client, we tested the script using a web browser, a couple of command line tools, and the ESP8266-based data logger, itself.
In this third and final part of the series, I discuss using JSON and XML data exchange formats to send data to web clients, how to implement Secure Hyper Text Transport Protocol (HTTPS) communications between the ESP8266-based data logger and the web server, and how to secure SQL transactions with the database to avoid the infamous “SQL injection” attack. I also explain briefly the implementation of a basic frontend webpage for graphically visualizing sensor data on a web browser, using HTML, CSS and JavaScript.
To properly follow the topics discussed here, it is advisable to refer back to Part 1 [1] and Part 2 [2] of this article series. All source code for the examples discussed here are available on the Circuit Cellar Article Materials and Resources webpage.
GENERATING JSON AND XML
We learned how to retrieve previously stored sensor data from the database and send them back to requesting web clients as CSV files, in Part 2 of this series. CSV is a data exchange format that lends itself well to work with microcontroller (MCU)-based web clients, because it is memory-efficient. It works well with small datasets, but with bigger ones, it has drawbacks due to being less clearly defined as a format. It is not structurally hierarchical and not easily scalable, in comparison to JavaScript Object Notation (JSON) and Extensible Markup Language (XML) formats.
In contrast, JSON and XML are better for larger and structurally complex datasets. This is not the case for the simple examples presented in this article. Nevertheless, it is important to discuss how to generate JSON and XML formats, because they are widely used to exchange data between servers and clients. On the one hand, JSON is more efficient than XML in terms of memory space and bandwidth, but less efficient than CSV. Still, it is used with MCUs in specific circumstances. On the other hand, XML can be pretty inefficient when used with MCUs, but it is commonly used with web browsers.
Let’s see how to generate a JSON file from previously stored sensor data in the database. The process is almost the same as for the CSV case explained previously [2]. Listing 1 is an excerpt of the fetch_json.php script that generates and sends back the JSON file. The listing only shows the Fetch_Db_Json() PHP function that fetches data from the database and generates the JSON file. The rest of the code (not shown in the listing) is the same as in the PHP script that generates CSV data.
Line 4 in the listing builds the SQL query to fetch the data, and line 5 queries the database—the same as with the CSV example given previously [2]. If there’s at least one result (line 7), line 9 uses the mysqli_fetch_all() PHP function to fetch all available results, and stores them in the $rows associative array. In PHP, an associative array is a data array that uses string keys to access data cells, instead of integer indexes, as with regular C-language arrays. For instance, once fetched, all data from $result, the first temperature value can be accessed indexing the array as $rows[0][‘temperature’], and the pressure value can be accessed as $rows[0][‘pressure’]. The same applies to the rest of the table columns. Finally, line 10 uses the json_encode() PHP function to encode the associative array into a JSON string. Then it uses the echo construct to send the JSON string to the requesting client.
Generating XML data requires essentially a similar procedure. Listing 2 contains an excerpt of the fetch_xml.php script that generates the XML file. This script is also similar to the CSV and JSON ones, except for the corresponding Fetch_Db_Xml() function. In particular, lines 9-24 are in charge of generating the XML file. Here, XML is “manually” generated, because there is not an off-the-shelf PHP function that generates an XML string from an array. Even so, doing it manually is simple for the data size we are managing in our examples. Besides, going a bit lower in the abstraction level here is good to get us further acquainted with the PHP programming language. This is particularly true regarding the manipulation of strings, which is a common task when using PHP as a server-side scripting language.
LISTING 1
Code for the "fetch_json.php" script.
1 <?php2 // ...3 function Fetch_Db_Json($conn, $from_date_hour, $to_date_hour) {4 $query = “SELECT * FROM sensors WHERE unix_t BETWEEN ‘$from_date_hour’ AND ‘$to_date_hour’ ORDER BY unix_t”;5 $result = $conn->query($query); // Query the DB6 7 if ($result->num_rows > 0) { //If there’s at least one row...8 // Fetch all results into an associative array9 $rows = mysqli_fetch_all($result, MYSQLI_ASSOC);10 echo json_encode($rows); // Send as JSON11 } else { // No results matching search criteria...12 echo “0 results”; // Send feedback to web client13 }14 }15 ?>
LISTING 2
Code for the "fetch_xml.php" script.
1 <?php2 // ...3 function Fetch_Db_Xml($conn, $from_date_hour, $to_date_hour) {4 $sql = “SELECT * FROM sensors WHERE unix_t BETWEEN ‘$from_date_hour’ AND ‘$to_date_hour’ ORDER BY unix_t”;5 $result = $conn->query($sql); // Query the DB6 7 if ($result->num_rows > 0) { //If there’s at least one row...8 // Build the XML file9 header(“Content-type: text/xml”);10 echo “<?xml version=’1.0’ ?>”; // Begin XML file11 echo ‘<readings>’; // Insert root node12 13 // Insert row data into the XML file14 while($row = $result->fetch_assoc()) {15 //Add XML elements w/ sensor readings as attributes16 echo ‘<reading ‘;17 echo ‘unix_t=”’ . $row[“unix_t”] . ‘” ‘;18 echo ‘gas_res=”’ . $row[“gas_res”] . ‘” ‘;19 echo ‘pressure=”’ . $row[“pressure”] . ‘” ‘;20 echo ‘temperature=”’ . $row[“temperature”] . ‘” ‘;21 echo ‘rel_hum=”’ . $row[“rel_hum”] . ‘”’;22 echo ‘/>’;23 }24 echo ‘</readings>’; // Close the parent node25 } else { // No results matching fetch criterion...26 echo “0 results”; // Send feedback to web client27 }28 }29 ?>
To understand how this code generates the XML string, you must be familiar with XML structure. Please refer to the Circuit Cellar Article Materials and Resources webpage for a link to a suggested tutorial about XML structure. Line 9 inserts the content type specification in the HTTP response’s header the server will send to the requesting client. Line 10 begins the XML file properly by inserting the so-called “XML declaration” as a first line, which basically states the XML specification version. Line 11 inserts the opening tag for the root node or root element. Any names can be used for the nodes or elements in an XML file, as long as the XML naming rules are followed. I chose <readings> for the root element, since the XML file will contain one or more sensor readings batches.
Next, in lines 14-23 we iterate over every available $row retrieved from the database table to insert nested or children elements in the XML structure, each for every row available. Line 16 inserts the tag for the current row of sensor readings. Next, lines 17-21 insert five parameters for the current “reading” child element corresponding with the names and values of each sensor reading. For instance, line 17 inserts unix_t as a parameter, followed by the Unix time value for the current row ($row[‘unix_t’]), and so on. Here, string concatenation is used to achieve the desired text structure. Line 24 inserts the closing tag for the root element.
String concatenation in PHP seems confusing at first. If you are getting that vibe, please search for any PHP string concatenation tutorial on the Internet. Once you see a few more examples, it should be easier to understand.
To test the fetch_json.php script on a web browser, after changing the relevant tokens, enter the following Uniform Resource Identifier (URI) on your web browser’s address bar:
http://192.168.0.110/backend/fetch_json.php?from_date=2023-08-08&to_date=2023-08-08
Note that before using the URI above, you must change at least the IP address of your server and the “from” and “to” dates to a period of days for which you have data stored in your database. Figure 1 is a screen capture of my web browser, showing the result of accessing the above URI on my web server.
Similarly, to test the fetch_xml.php script, just replace fetch_json.php with fetch_xml.php in the above URI to get something like the following:
http://192.168.0.110/backend/fetch_xml.php?from_date=2023-08-08&to_date=2023-08-08
The corresponding web browser screen capture with the resulting XML file is shown in Figure 2.
A SECURE WEB SERVER
To enable HTTPS on our web server and make it secure, we must provide it with an SSL/TLS server certificate. This normally requires the server to have a domain name globally accessible. It is possible to implement HTTPS on a Raspberry Pi-based Local Area Network (LAN) server by providing it with a domain name and a SSL/TLS server certificate; however, it is a somewhat involved process. Regardless, it really doesn’t make much sense to implement HTTPS on a local server, because SSL/TLS encryption and server certificates are really for verifying Internet web servers. In that vein, testing HTTPS requests is much easier using, for example, a paid server and domain name from a hosting provider. Nowadays, you can have one of those with an included SSL/TLS certificate for less than $15 a month. Those paid servers come already set up with LAMP software, so you just have to upload your web application files to your server’s directory, create your database, and you are good to go.
Most of these hosting providers have good tutorials on how to set up your web application files and create your database. In general, setting up the web application involves just uploading the PHP scripts to a given directory in the server file system, and that’s it. The database, user, and table are created using web control panels in your hosting account and the phpMyAdmin MySQL/MariaDB web interface. Because the latter is a graphical interface, it is even easier than using the Linux terminal, which we did in previous parts of this article series. Links to articles explaining how to upload the web application files and set up a database on a popular web hosting service are included on the Circuit Cellar Article Materials and Resources webpage. So, for the following tests with HTTPS requests, I used a paid server from a web hosting provider, such as the one described previously.
ARDUINO HTTPS
There are basically three ways to make HTTPS requests from an ESP8266 MCU to a web server using the Arduino platform:
- requests without a certificate;
- requests with a fingerprint; and
- requests with a server root certificate [3].
Option 1 skips SSL/TLS server certificate verification altogether, and is useful for rapid prototyping and testing. Option 2 uses server fingerprint verification, with the downside being that fingerprint validity is usually very short. With this method, because the fingerprint is statically defined in the source code, the ESP8266 needs to be re-flashed frequently. Option 3 is the best of the three, because it verifies the server’s root certificate. Root certificates are valid for more than 5 years, so with this method the ESP8266 doesn’t need to be re-flashed frequently.
Previously in this article series, we tested the Arduino sketches esp8266_http_post_client and esp8266_http_get_csv for the ESP8266-based data logger. The first one sends sensor data to the web server to be stored in the database. The second one requests previously stored sensor data from the database, and puts them in CSV format. As you will see next, it doesn’t take much to modify these sketches to make them work with HTTPS, using server root certificate verification. Listing 3 shows the necessary modifications to the esp8266_http_get_csv sketch to use HTTPS instead of HTTP.
LISTING 3
Requesting CSV data from the server using HTTPS
1 #include <ESP8266WiFi.h>2 #include <WiFiClientSecure.h>3 #include <ESP8266HTTPClient.h>4 // ...5 6 // Root certificate 7 const char IRG_Root_X1 [] PROGMEM = R”CERT(8 -----BEGIN CERTIFICATE-----9 MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw10 TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh11 cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM412 // [...] Some lines were cut for brevity13 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA14 mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d15 emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=16 -----END CERTIFICATE-----17 )CERT”;18 19 // Create a list of certificates with the server certificate20 X509List cert(IRG_Root_X1);21 22 void setup() {23 // ...24 // Set time via NTP, as required for x.509 validation25 configTime(3 * 3600, 0, “pool.ntp.org”, “time.nist.gov”);26 27 Serial.print(“Waiting for NTP time sync: “);28 time_t now = time(nullptr);29 while (now < 8 * 3600 * 2) {30 delay(500);31 Serial.print(“.”);32 now = time(nullptr);33 }34 Serial.println(“”);35 struct tm timeinfo;36 gmtime_r(&now, &timeinfo);37 Serial.print(“Current time: “); Serial.print(asctime(&timeinfo));38 }39 40 void loop() {41 // ...42 Send_Get_Request(); // Send the HTTPS request43 // ...44 }45 46 // Send the HTTPS request47 void Send_Get_Request() {48 if ((WiFi.status() == WL_CONNECTED)) {49 WiFiClientSecure client;50 client.setTrustAnchors(&cert);51 HTTPClient https;52 53 Serial.print(“[HTTPS] begin...\n”);54 if (https.begin(client, PHP_SCRIPT_URI + get_query_string)) { 55 // Start connection and send HTTP header56 // ...57 58 https.end();59 } else {60 Serial.printf(“[HTTPS] Unable to connect\n”);61 }62 }63 }
Line 3 shows the inclusion of the WiFiClientSecure Arduino library to add support for secure connections using SSL/TLS, making possible the use of HTTPS. Lines 7-17 define the web server root SSL/TLS certificate corresponding to my web server. It will be used to authenticate communications with the server. In my case, this is the root certificate of the paid shared server from the web hosting company. Server root certificates are easily obtained by inspecting the site information on a web browser [3].
Because root certificates are valid for more than 5 years, it will not be necessary to modify the sketch often. So, when using HTTPS, every time we make a request to our server, the sketch will verify if the received server certificate matches the certificate defined in the Arduino sketch. Line 20 creates a list of certificates to verify servers—in this case, with just one certificate: the one previously defined.
Going forward, in the setup function, lines 25-37 sets the ESP8266 MCU’s “local” time by synchronizing it using Network Time Protocol (NTP) to Internet time servers. This is required for the X.509 standard (which defines the format of public key certificates) to perform certificate validation. The loop() function doesn’t change at all in comparison with the plain HTTP version. It still calls the Send_Get_Request() function, but now this function sends an HTTPS request instead of an HTTP request (line 42). The aforementioned function is defined in lines 47-63.
Only the most relevant code lines are shown here, as with the rest of this code listing. If the Wi-Fi connection was established successfully (line 48), we create now a WiFiClientSecure client (line 49), instead of a plain WiFiClient, as in the HTTP version. Next, with line 50, we attach to our secure client the certificate list of trusted servers created before. From this point on, the rest of the code is practically the same as in the plain HTTP example.
By making the same few changes to the rest of the Arduino sketches, we obtain their HTTPS versions: esp8266_https_get_csv.ino, esp8266_https_get_json.ino, and esp8266_https_post_client.ino. All these HTTPS versions are available on the Circuit Cellar Article Materials and Resources webpage.
PREVENTING SQL INJECTION
Like other web technologies, PHP and SQL have their own security vulnerabilities [4]. Obviously, it will not be possible to talk about all of them here, but at least we can discuss one of the most well known, called “SQL injection.” SQL injection works by pushing unsanitized SQL queries to the database, such that the database returns information not originally intended by the web application. How is it done? By pushing purposefully ill-formed data to the web application PHP scripts, so that they will be inserted into the SQL queries, thereby tricking the web application into providing data not originally intended to be accessible [5].
One easy way to prevent SQL injection attacks is by using parameterized queries and prepared statements in PHP with input sanitation, instead of plain-text queries. Listing 4 shows modifications to the receive_csv.php script to use a parameterized query. Aside from reordering some lines, the main difference in this listing with the original non-parameterized version is in lines 13-27. With line 13, we prepare the SQL query, but this time, instead of inserting values in the VALUES parenthesis, we insert five “?” characters as parameter holders.
LISTING 4
'receive_csv.php' with parameterized SQL query.
1 <?php 2 // Get the body (CSV string) from the incoming request3 $csv = file_get_contents(‘php://input’); 4 $data_array = str_getcsv($csv); // Convert CSV to array5 6 if($data_array != null) {7 // Connect to the database8 require_once ‘login.php’; // Include the script with database login information9 $conn = new mysqli($server, $user, $password, $database);10 if ($conn->connect_error) die($conn->connect_error); 11 12 // Prepare and bind13 $query = “INSERT INTO sensors (unix_t, gas_res, pressure, temperature, rel_hum) VALUES (?, ?, ?, ?, ?)”;14 $stmt = $conn->prepare($query);15 $stmt->bind_param(“idddd”, $unix_t, $gas_res, $pressure, $temperature, $rel_hum);16 17 // Set parameters and execute18 $unix_t = time(); // Read unix time (GMT) from server19 $gas_res = $data_array[0]; 20 $pressure = $data_array[1];21 $temperature = $data_array[2];22 $rel_hum = $data_array[3];23 24 $stmt->execute();25 26 $stmt->close();27 $conn->close();28 } 29 ?>
Next, in line 14 the query is prepared. In line 15, we bind the five parameters to local variables. The string “idddd” in the bind_param() function sets the data types for the five parameters: “i” for integer, and “d” for double. So, the first parameter is an integer, and the four others are doubles. In lines 18-22 we fill the parameter variables with corresponding values, and with line 24 the query is executed. For simplicity, we are assuming the query will execute without errors, so we are neither trying to catch them, nor printing error messages. The other PHP scripts for fetching data in CSV, JSON and XML formats have similar modifications. All these new versions are also available for download from Circuit Cellar‘s Article Materials and Resources web page.
FRONTEND EXAMPLE
Although this article series focuses on backend development, for completeness’ sake, I would like to present a basic frontend example for the type of backend we have been developing in this series. Typical frontend development is mostly done for webpages accessed by people (not MCUs!) via web browsers. For IoT applications, the aim of the frontend will be, for instance, to visualize sensor data, and sometimes also to configure remote IoT devices, among other things.
Let’s describe a basic dynamic webpage to graphically display sensor data stored in a database. I really don’t expect you to understand all that will be discussed in this part, because frontend development deserves an article series of its own to discuss it properly.
We begin by describing a base workflow for displaying sensor data on a webpage (Figure 3). The same backend structure I discussed in Part 1 of this article series [1] is shown. The frontend, however has some differences. First, here the frontend aims primarily at web browsers running on personal computers or mobile devices. Second, the languages used for the web client are now HTML, CSS, and JavaScript. We still use POST/GET HTTP requests to talk to the server, though, and the server sends back data in JSON and XML formats. CSV, however, generally is not used to send data to webpages.
I am not going to go into great detail here about how to develop dynamic webpages. I will just explain the basics about the technologies involved, the data exchange from the server to the web client, and the dynamic graphic visualization. First, I’ll explain the role played by HTML, CSS, and JavaScript when building a dynamic webpage. HTML is a standard markup language for creating webpages. It consists of a series of elements that describe the structure of a webpage, which a web browser interprets to display the intended content. Such elements refer to typical components in most webpages, such as text headings, paragraphs, hyperlinks, images, input forms, buttons, and controls. So, in essence, HTML manages the structure and visualization of a webpage.
CSS describes how the HTML elements of the webpage will be displayed, and also helps to control the page layout. In other words, CSS helps to define the styling and look of a webpage. So, CSS complements HTML by helping with the styling, but it is not essential for a webpage. A webpage without CSS will still work and will be displayed by a web browser, though it will look kind of raw and bare-boned.
Finally, JavaScript is the programming language that helps bring dynamic content and interactivity to an otherwise static HTML/CSS webpage. Unlike HTML and CSS, which are markup and styling languages, respectively, JavaScript is a programming language in every sense of the word. As a matter of fact, JavaScript is the actual frontend programming language for the Web.
Figure 4 shows the frontend example I prepared for illustration purposes. For simplicity, the webpage uses mostly HTML and JavaScript, with almost no CSS styling. The JavaScript code embedded in the page queries sensor data from the web server, and displays it as a 2D graph timeline, using the Plotly JavaScript library [6]. The index.html source code for the webpage is shown in Listing 5. Without going into much detail, lines 13-21 contain the input controls for the “from” and “to” dates to select the visualization time period on the page, along with the “Send query” checkbox control. Line 26 defines the section in the page that will contain the 2D graph timeline with the sensor readings. Line 29 is an inclusion line that requests the view_graph.js JavaScript file from the web server. This file contains all code written to display dynamic content on the webpage. Lines 31 and 33 request two JavaScript libraries: jquery.min.js and plotly-latest.min.js. Both are downloaded from their own respective web servers (ajax.googleapis.com and cdn.plt.ly). These two libraries are used by the view_graph.js code. The first one is used to make AJAX HTTPS requests to our web server, and the second one is used to plot the 2D graph.
Finally, Listing 6 shows an excerpt from the view_graph.js JavaScript code. It contains only two functions, and the rest of the code is omitted for brevity. The queryServer() function receives the “from” and “to” dates, and sends an HTTPS GET request to the web server, using the jQuery JavaScript library. In addition, the updatePage() function receives as argument the XML document received back from the web server (line 16), parses all sensor data, and stores them into a dictionary of arrays (lines 27-40). Then it calls the update2DGraph() function (line 41), which uses the Plotly JavaScript library to generate the 2D sensor data graph shown in Figure 4. Both frontend webpage files are also available for download from Circuit Cellar‘s Article Materials and Resources web page. After changing your database login credentials in the login.php file, they should work for you without any changes, along with the rest of the PHP scripts—if you followed all steps outlined in this series.
CONCLUSION
Upgrading the ESP8266-based data logger to do HTTPS requests wasn’t complicated at all, thanks to the available Arduino HTTPS libraries. Minimal changes were required to make our HTTP sketches work with HTTPS. However, we also saw that HTTPS is actually for connecting with servers on the Internet. It really doesn’t make much sense to use HTTPS on a Local Area Network (LAN). Furthermore, it is tricky to implement HTTPS on a LAN server, because normally for HTTPS, the server needs a globally accessible domain name anyway. For that reason, to test HTTPS, it is more convenient to develop the web application using an Internet web server. For example, a simple shared server from a web hosting company will work well.
Regarding basic SQL security, we saw that preventing SQL injection is also straightforward. Granted, there’s still much to say and do concerning web application security in general.
Finally, a basic frontend webpage that graphically visualizes sensor data on a web browser was presented. Frontend web development is a separate topic in and of itself, but I hope that the example I used gave you a taste of what is involved with working on the frontend side, to have sort of a complete picture regarding full-stack web development for IoT. I hope you enjoyed the series!
In the final part of this series, I discuss the generation of JSON and XML files to send sensor data from the web and database servers to web clients. I also cover upgrading the system from HTTP to HTTPS with the use of an Internet web server on a shared web hosting service. Finally, as a complement to backend development for IoT discussed in the series, I present an example of a frontend web page to graphically display sensor data on a web browser.
REFERENCES
[1] Raul Alvarez-Torrico, “Backend Web Development for MCU Clients. Part 1. Handling HTTP Requests in PHP.” Circuit Cellar 399, October 2023.
[2] Raul Alvarez-Torrico, “Backend Web Development for MCU Clients. Part 2. Querying a Database in PHP.” Circuit Cellar 400, November, 2023.
[3] ESP8266 NodeMCU HTTPS Requests, https://randomnerdtutorials.com/esp8266-nodemcu-https-requests/
[4] Top 7 PHP Security Issues And Vulnerabilities, https://spectralops.io/blog/top-7-php-security-issues-and-vulnerabilities/
[5] SQL Injection, https://www.w3schools.com/sql/sql_injection.asp
[6] Plotly JavaScript Open Source Graphing Library, https://plotly.com/javascript/
SOURCES
— ADVERTISMENT—
—Advertise Here—
ESP8266 NodeMCU CP2102 ESP-12E Development Board
https://www.amazon.com/HiLetgo-Internet-Development-Wireless-Micropython/dp/B010O1G1ES
Adafruit BME688 – Temperature, Humidity, Pressure and Gas Sensor – STEMMA QT
https://www.adafruit.com/product/5046
How to Upload a File Using the File Manager?
https://www.hostgator.com/help/article/how-to-upload-a-file-using-the-file-manager
How To Create or Delete a MySQL Database or User
https://www.hostgator.com/help/article/how-do-i-create-a-mysql-database-a-user-and-then-delete-if-needed
How to add tables to a database in phpMyAdmin
https://www.hostgator.com/help/article/how-to-add-tables-to-a-database-in-phpmyadmin
RESOURCES
Espressif Systems | www.espressif.com
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JANUARY 2024 #402 – Get a PDF of the issue
Sponsor this ArticleRaul Alvarez Torrico has a B.E. in electronics engineering and is the founder of TecBolivia, a company offering services in physical computing and educational robotics in Bolivia. In his spare time, he likes to experiment with wireless sensor networks, robotics and artificial intelligence. He also publishes articles and video tutorials about embedded systems and programming in his native language (Spanish), at his company’s web site www.TecBolivia.com. You may contact him at raul@tecbolivia.com





