This shows you the differences between two versions of the page.
| — |
iothings:laboratoare:2025_code:lab8_3 [2025/11/15 13:21] (current) dan.tudose created |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | <code C++ main.cpp> | ||
| + | #include <Arduino.h> | ||
| + | #include <WiFi.h> | ||
| + | #include <WiFiClientSecure.h> | ||
| + | #include <HTTPClient.h> | ||
| + | #include <pgmspace.h> | ||
| + | // ===================== LAB CONFIG ===================== | ||
| + | |||
| + | // Wi-Fi credentials | ||
| + | const char* WIFI_SSID = "LAB_WIFI_SSID"; | ||
| + | const char* WIFI_PASSWORD = "LAB_WIFI_PASSWORD"; | ||
| + | |||
| + | // Server hostname and port. | ||
| + | // Hostname MUST match the CN/SAN in your server certificate (e.g. "iot-lab.local"). | ||
| + | const char* SERVER_HOST = "iot-lab.local"; | ||
| + | const uint16_t SERVER_PORT = 8443; | ||
| + | |||
| + | // URL used by HTTPClient (hostname + port + path) | ||
| + | const char* SERVER_URL = "https://iot-lab.local:8443/ingest"; | ||
| + | |||
| + | // Device identity | ||
| + | const char* DEVICE_ID = "sparrow-01"; | ||
| + | |||
| + | // MAC secret key – must match SECRET_KEY in secure_server.py | ||
| + | const char* SECRET_KEY = "LAB2_SUPER_SECRET_MAC_KEY"; | ||
| + | |||
| + | // Root CA certificate (PEM), copied from ca.crt. | ||
| + | // Replace the placeholder contents with your actual CA cert. | ||
| + | static const char LAB_ROOT_CA[] PROGMEM = R"EOF( | ||
| + | -----BEGIN CERTIFICATE----- | ||
| + | PASTE_YOUR_CA_CERT_HERE | ||
| + | -----END CERTIFICATE----- | ||
| + | )EOF"; | ||
| + | |||
| + | // ====================================================== | ||
| + | |||
| + | WiFiClientSecure secureClient; | ||
| + | |||
| + | // Very simple, non-cryptographic MAC, must match server's compute_mac() | ||
| + | uint32_t computeMac(const String& payload, const char* secret) { | ||
| + | String data = payload + secret; | ||
| + | uint32_t h = 0; | ||
| + | for (size_t i = 0; i < data.length(); i++) { | ||
| + | uint8_t b = static_cast<uint8_t>(data[i]); | ||
| + | h = (h * 31) ^ b; | ||
| + | } | ||
| + | return h; | ||
| + | } | ||
| + | |||
| + | void connectToWiFi() { | ||
| + | Serial.printf("Connecting to WiFi SSID: %s\n", WIFI_SSID); | ||
| + | WiFi.mode(WIFI_STA); | ||
| + | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); | ||
| + | |||
| + | uint8_t retries = 0; | ||
| + | while (WiFi.status() != WL_CONNECTED && retries < 30) { | ||
| + | delay(500); | ||
| + | Serial.print("."); | ||
| + | retries++; | ||
| + | } | ||
| + | |||
| + | if (WiFi.status() == WL_CONNECTED) { | ||
| + | Serial.println("\nWiFi connected!"); | ||
| + | Serial.print("IP address: "); | ||
| + | Serial.println(WiFi.localIP()); | ||
| + | } else { | ||
| + | Serial.println("\nFailed to connect to WiFi"); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(115200); | ||
| + | delay(2000); | ||
| + | |||
| + | connectToWiFi(); | ||
| + | |||
| + | secureClient.setTimeout(15000); | ||
| + | |||
| + | // Load CA certificate so the ESP32 can verify the server's cert. | ||
| + | if (!secureClient.setCACert(LAB_ROOT_CA)) { | ||
| + | Serial.println("Failed to load CA certificate!"); | ||
| + | } else { | ||
| + | Serial.println("CA certificate loaded."); | ||
| + | } | ||
| + | |||
| + | randomSeed(esp_random()); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | if (WiFi.status() != WL_CONNECTED) { | ||
| + | Serial.println("WiFi disconnected, reconnecting..."); | ||
| + | connectToWiFi(); | ||
| + | } | ||
| + | |||
| + | if (WiFi.status() == WL_CONNECTED) { | ||
| + | // Fake sensor data (same ranges as before) | ||
| + | float tempC = 20.0 + (random(0, 1000) / 100.0f); // 20.00–29.99 | ||
| + | float humidity = 40.0 + (random(0, 1000) / 50.0f); // 40.0–59.9 | ||
| + | int battery = random(60, 100); // 60–99 % | ||
| + | |||
| + | // Build JSON WITHOUT MAC first, in canonical key order: | ||
| + | // battery, device_id, humidity, temp_c | ||
| + | // This must match the server's json.dumps(sort_keys=True,separators=(",",":")) | ||
| + | String jsonNoMac = "{"; | ||
| + | jsonNoMac += "\"battery\":" + String(battery) + ","; | ||
| + | jsonNoMac += "\"device_id\":\"" + String(DEVICE_ID) + "\","; | ||
| + | jsonNoMac += "\"humidity\":" + String(humidity, 1) + ","; | ||
| + | jsonNoMac += "\"temp_c\":" + String(tempC, 2); | ||
| + | jsonNoMac += "}"; | ||
| + | |||
| + | // Compute MAC over jsonNoMac + SECRET_KEY | ||
| + | uint32_t mac = computeMac(jsonNoMac, SECRET_KEY); | ||
| + | |||
| + | // Full JSON payload including MAC | ||
| + | String payload = "{"; | ||
| + | payload += "\"battery\":" + String(battery) + ","; | ||
| + | payload += "\"device_id\":\"" + String(DEVICE_ID) + "\","; | ||
| + | payload += "\"humidity\":" + String(humidity, 1) + ","; | ||
| + | payload += "\"temp_c\":" + String(tempC, 2) + ","; | ||
| + | payload += "\"mac\":" + String(mac); | ||
| + | payload += "}"; | ||
| + | |||
| + | Serial.println("Sending HTTPS POST to server (with cert validation)..."); | ||
| + | Serial.println("URL: " + String(SERVER_URL)); | ||
| + | Serial.println("Payload: " + payload); | ||
| + | |||
| + | HTTPClient http; | ||
| + | |||
| + | // Begin HTTPS connection with certificate verification. | ||
| + | if (!http.begin(secureClient, SERVER_URL)) { | ||
| + | Serial.println("Failed to start HTTP connection"); | ||
| + | } else { | ||
| + | http.addHeader("Content-Type", "application/json"); | ||
| + | |||
| + | int httpCode = http.POST(payload); | ||
| + | if (httpCode > 0) { | ||
| + | Serial.printf("HTTP response code: %d\n", httpCode); | ||
| + | String response = http.getString(); | ||
| + | Serial.println("Response body: " + response); | ||
| + | } else { | ||
| + | Serial.printf("HTTP POST failed, error: %s\n", http.errorToString(httpCode).c_str()); | ||
| + | } | ||
| + | |||
| + | Serial.println("-----------------------------"); | ||
| + | http.end(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | delay(5000); // send every 5 seconds | ||
| + | } | ||
| + | |||
| + | </code> | ||