Arduino and IoT: from Wi‑Fi to a web server and the cloud

ARDUINO COURSE

Connecting a microcontroller to the network and online services is at the heart of the Internet of Things. Arduino, with its many boards and libraries, lets you build prototypes and stable solutions capable of reading sensors, serving local web pages, and sending telemetry to cloud platforms. In this guide you’ll learn the key steps to connect your project to the Wi‑Fi network, build a small web server to view data on your LAN, and forward measurements to remote APIs or brokers securely and reliably.

Components and tools: what you really need

Before you write a line of code, it’s helpful to clarify the most suitable hardware and software ecosystem. Not all boards have built‑in Wi‑Fi, and the choice of library depends on the hardware you’re using.

  • Recommended boards:
    • ESP32 or ESP8266: built‑in Wi‑Fi, low cost, large community.
    • Arduino Nano 33 IoT or MKR WiFi 1010: built‑in WiFiNINA and official support.
    • Arduino UNO (with Wi‑Fi shield or external module): a viable option but with tighter memory constraints.
  • Main libraries:
    • ESP32/ESP8266: WiFi.h, HTTPClient, WiFiClientSecure, PubSubClient (for MQTT).
    • Nano 33 IoT/MKR: WiFiNINA, ArduinoHttpClient, PubSubClient.
  • Software:
    • Arduino IDE or Arduino IDE 2 with an up‑to‑date Board Manager.
    • Drivers for the chosen board and libraries installed via the Library Manager.
    • An account on a cloud service (e.g., ThingSpeak, Adafruit IO, a REST endpoint on your own server, or an MQTT broker like Eclipse Mosquitto).

Connecting to the Wi‑Fi network

Choosing the library and preparation

On ESP32/ESP8266 you’ll use the WiFi.h library, while on Nano 33 IoT/MKR WiFi 1010 the library is WiFiNINA. The approach is similar: set station mode (STA), start the connection with SSID and password, and wait for it to connect.

Example: connect to a network with ESP32

The following example shows a basic connection, printing the IP address obtained via DHCP. Remember to replace the SSID and password.

// ESP32: basic Wi‑Fi connection
#include 

const char* ssid     = "YOUR_WIFI_NETWORK";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {
  Serial.begin(115200);
  delay(1000);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.println(" in progress...");

  int tentativi = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    tentativi++;
    if (tentativi > 60) {
      Serial.println("nTimeout: restarting...");
      ESP.restart();
    }
  }

  Serial.println("nConnected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // Here you can read sensors or send data
  delay(1000);
}

Practical tips: in environments with static IPs, consider a static address; set up a reconnection mechanism after signal loss; avoid blocking the loop with endless waits.

Create a small local web server

An embedded web server lets you quickly check device status and share sensor readings on the local network without exposing access to the Internet. You can respond with plain text or provide REST‑style endpoints for local apps or dashboards.

Example: server on port 80 (ESP32)

This example starts a minimal HTTP server that replies with textual content to avoid HTML complications. Open the IP address in your browser to read the status.

// ESP32: minimal HTTP server (text)
#include 

WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  // Assumes the Wi‑Fi connection has already been established
  server.begin();
  Serial.println("Server started: visit http://DEVICE_IP/");
}

void loop() {
  WiFiClient client = server.available();
  if (!client) return;

  // Waits for data from the client
  unsigned long start = millis();
  while (client.connected() && !client.available() && millis() - start < 2000) {
    delay(1);
  }

  if (!client.available()) {
    client.stop();
    return;
  }

  // Reads the first line of the HTTP request
  String requestLine = client.readStringUntil('r');
  client.readStringUntil('n'); // consume the newline

  // Example: you can parse requestLine for different routes
  String body = "Device activenTemperature: 23.4 CnUptime (ms): " + String(millis());

  // HTTP response
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/plain; charset=utf-8");
  client.println("Connection: close");
  client.println();
  client.print(body);
  client.stop();
}

Want to separate data from presentation? Expose an /api/sensors endpoint that returns JSON and, if you want a web page, create a lightweight frontend (even on another host) that consumes the API. Alternatively, to handle multiple routes with less code, consider libraries like WebServer (ESP32) or ESPAsyncWebServer.

Send telemetry and logs to the cloud

When data needs to be persisted, correlated, and viewed remotely, sending it to the cloud is the natural choice. Two very common paths: HTTP/REST and MQTT. The former is straightforward if the provider exposes APIs; the latter is lighter and designed for event‑driven messaging.

HTTP/REST: example of a POST with JSON

With ESP32 you can use HTTPClient; for HTTPS, use WiFiClientSecure. For simplicity, the following example disables certificate verification (don’t do this in production): instead configure the destination’s fingerprint or CA certificate.

// ESP32: send JSON to an HTTPS endpoint
#include 
#include 
#include 

const char* endpoint = "https://api.example.com/telemetry";
const char* token    = "INSERT_YOUR_TOKEN";

void inviaDati(float temperatura, float umidita) {
  WiFiClientSecure client;
  client.setInsecure(); // FOR TESTING ONLY

  HTTPClient http;
  if (!http.begin(client, endpoint)) {
    Serial.println("HTTP initialization error");
    return;
  }

  http.addHeader("Content-Type", "application/json");
  http.addHeader("Authorization", String("Bearer ") + token);

  String payload = String("{"device":"esp32-01","temp":") + String(temperatura, 1) +
                   String(","hum":") + String(umidita, 1) + String("}");

  int code = http.POST(payload);
  if (code > 0) {
    Serial.print("HTTP ");
    Serial.println(code);
    String risposta = http.getString();
    Serial.println(risposta);
  } else {
    Serial.print("POST error: ");
    Serial.println(http.errorToString(code));
  }
  http.end();
}

Many services offer SDKs or ready‑made telemetry endpoints. ThingSpeak accepts POST requests with an API key; platforms like InfluxDB or TimescaleDB integrate well via gateways such as Telegraf; for custom solutions, an API on a server or a serverless function (AWS Lambda, Cloud Functions) is a flexible choice.

MQTT: lightweight and reliable

For publish/subscribe scenarios and frequent updates, MQTT is often ideal. PubSubClient lets you connect to public or self‑hosted brokers. Best practices: use TLS (port 8883), credentials for dedicated topics, retain only when necessary, QoS 1 for guaranteed delivery, and a Last Will to signal disconnections.

Security, stability, and maintenance

Even in prototypes, protecting credentials is crucial. Avoid hardcoding keys in the main file: move them to a separate, untracked header or use a secure provisioning system. Always prefer encrypted connections (HTTPS/MQTTs) with certificate verification; sync the clock via NTP to validate TLS correctly. Implement automatic reconnection, hardware/software watchdogs, and minimal logs to understand field errors. If the project will live for a long time, plan OTA updates to fix bugs without physical intervention.

Debug and testing: from the first pings to validation

A progressive testing path reduces complexity and makes diagnosis easier:

  • Check the network: verify SSID/password and signal strength; assign a reserved IP via DHCP if possible.
  • Confirm connectivity: ping the device’s IP from the LAN and test the server by opening the address in a browser.
  • Validate the APIs: use curl or an HTTP client to test endpoints and payloads.
  • Watch serial logs: add clear messages for states, errors, and response times.
  • Simulate failures: turn off the router or broker to verify resilience and reconnection times.
# Test examples from a PC
ping DEVICE_IP
curl http://DEVICE_IP/
curl -X POST https://api.example.com/telemetry -H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" -d "{"test":true}"

Useful extensions for advanced projects

Once the foundation is solid, you can add features that improve usability and integration:

  • mDNS: access the device as http://my-device.local/ without remembering the IP.
  • WebSocket or SSE: real-time updates to the local dashboard.
  • Cache and batching: send samples at intervals to save energy and bandwidth.
  • Emergency AP mode: if Wi‑Fi isn’t configured, create a hotspot for onboarding.
  • Time management: NTP sync for accurate timestamps and TLS certificates.

Conclusions

With a few key steps you can turn a board into a smart node: network connection, local server for quick observability, and integration with remote services for analysis and automation. Focus on small iterations: first connect Wi‑Fi, then show data on the LAN, and finally add encrypted telemetry and error handling. You’ll build robust, scalable solutions ready to grow from prototype to product.

Ready to put your sensors online?

Open the IDE, try the examples above, and create your first status page. Then connect a real sensor and send the data to your preferred cloud. If you want step‑by‑step guides, ready‑made snippets, and tips on security and scalability, subscribe to our newsletter and share your project: we’ll be happy to help you take it further.

Se vuoi farmi qualche richiesta o contattarmi per un aiuto riempi il seguente form

    Comments