// Provider communication — mDNS discovery, device registration, screen fetch. #include "provider.hpp" #include #include #include "esp_log.h" #include "mdns.h" #include "sdkconfig.h" #include "http_client.hpp" #include "network.hpp" static const char *TAG = "Provider"; // ── mDNS Provider Discovery ──────────────────────────────────────────────── // Resolve the Provider's IP via mDNS. Returns true and fills `out_ip` on // success. Falls back to CONFIG_CALENDINK_PROVIDER_FALLBACK_IP if set. static bool resolve_provider_ip(char *out_ip, size_t out_ip_len) { ESP_LOGI(TAG, "Resolving Provider via mDNS: %s.local", CONFIG_CALENDINK_PROVIDER_MDNS_HOSTNAME); esp_err_t err = mdns_init(); if (err != ESP_OK) { ESP_LOGE(TAG, "mDNS init failed: %s", esp_err_to_name(err)); goto fallback; } { esp_ip4_addr_t addr = {}; constexpr int kMaxRetries = 3; for (int attempt = 1; attempt <= kMaxRetries; attempt++) { err = mdns_query_a(CONFIG_CALENDINK_PROVIDER_MDNS_HOSTNAME, 5000, &addr); if (err == ESP_OK) { snprintf(out_ip, out_ip_len, IPSTR, IP2STR(&addr)); ESP_LOGI(TAG, "Provider resolved: %s (attempt %d)", out_ip, attempt); return true; } ESP_LOGW(TAG, "mDNS attempt %d/%d failed: %s", attempt, kMaxRetries, esp_err_to_name(err)); } } fallback: if (strlen(CONFIG_CALENDINK_PROVIDER_FALLBACK_IP) > 0) { strlcpy(out_ip, CONFIG_CALENDINK_PROVIDER_FALLBACK_IP, out_ip_len); ESP_LOGW(TAG, "Using fallback IP: %s", out_ip); return true; } ESP_LOGE(TAG, "No fallback IP configured. Cannot reach Provider."); return false; } // ── Provider Communication Test ───────────────────────────────────────────── bool test_provider_communication(uint8 *out_buffer, size_t buffer_size) { bool success = false; // 1. Resolve Provider IP char provider_ip[16] = {}; if (!resolve_provider_ip(provider_ip, sizeof(provider_ip))) { return false; } uint16_t provider_port = CONFIG_CALENDINK_PROVIDER_PORT; // 2. Get our own MAC address uint8_t mac_bytes[6] = {}; esp_err_t err = get_mac_address(mac_bytes); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to get WiFi MAC: %s", esp_err_to_name(err)); return false; } char mac_str[18] = {}; snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac_bytes[0], mac_bytes[1], mac_bytes[2], mac_bytes[3], mac_bytes[4], mac_bytes[5]); ESP_LOGI(TAG, "Client MAC: %s", mac_str); // 3. Register with Provider: POST /api/devices/register // This may return "already_registered" — that's fine, we continue regardless. { char *url = http_build_url(provider_ip, provider_port, "/api/devices/register"); if (url != nullptr) { char json_body[64] = {}; snprintf(json_body, sizeof(json_body), "{\"mac\":\"%s\"}", mac_str); http_text_response_t resp = {}; err = http_post_json(url, json_body, &resp); if (err == ESP_OK) { ESP_LOGI(TAG, "Register response (%d): %s", resp.status_code, resp.body ? resp.body : "(empty)"); } else { ESP_LOGW(TAG, "Register request failed: %s (continuing anyway)", esp_err_to_name(err)); } free(resp.body); free(url); } } // 4. Fetch screen bitmap: GET /api/devices/screen.bin?mac=XX:XX:XX:XX:XX:XX { char path[80] = {}; snprintf(path, sizeof(path), "/api/devices/screen.bin?mac=%s", mac_str); char *url = http_build_url(provider_ip, provider_port, path); if (url == nullptr) { return false; } http_binary_response_t resp = {}; err = http_get_binary(url, &resp); if (err == ESP_OK && resp.status_code == 200) { ESP_LOGI(TAG, "Screen bitmap response: %zu bytes", resp.data_len); if (resp.data != nullptr && resp.data_len > 0) { size_t copy_size = (resp.data_len < buffer_size) ? resp.data_len : buffer_size; memcpy(out_buffer, resp.data, copy_size); success = true; // Debug: log first 10 bytes (should be 0xFF for white top-left pixels) ESP_LOGI(TAG, "First 10 bytes: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", out_buffer[0], out_buffer[1], out_buffer[2], out_buffer[3], out_buffer[4], out_buffer[5], out_buffer[6], out_buffer[7], out_buffer[8], out_buffer[9]); } } else { ESP_LOGE(TAG, "Screen bitmap request failed: %s (status %d)", esp_err_to_name(err), resp.status_code); } free(resp.data); free(url); } return success; }