diff --git a/app/src/lib/types/models.ts b/app/src/lib/types/models.ts index 614f29e..4be3b2d 100644 --- a/app/src/lib/types/models.ts +++ b/app/src/lib/types/models.ts @@ -17,37 +17,6 @@ export enum MessageTopic { rssi = 'rssi' } -export type WifiStatus = { - status: number - local_ip: number - mac_address: string - rssi: number - ssid: string - bssid: string - channel: number - subnet_mask: number - gateway_ip: number - dns_ip_1: number - dns_ip_2?: number -} - -export type KnownNetworkItem = { - ssid: string - password: string - static_ip_config: boolean - local_ip?: number - subnet_mask?: number - gateway_ip?: number - dns_ip_1?: number - dns_ip_2?: number -} - -export type WifiSettings = { - hostname: string - priority_RSSI: boolean - wifi_networks: KnownNetworkItem[] -} - export type vector = { x: number; y: number } export type GithubRelease = { @@ -59,18 +28,6 @@ export type GithubRelease = { }> } -export type NetworkList = { - networks: NetworkItem[] -} - -export type NetworkItem = { - rssi: number - ssid: string - bssid: string - channel: number - encryption_type: number -} - export type Rssi = { rssi: number ssid: string diff --git a/app/src/routes/wifi/sta/Scan.svelte b/app/src/routes/wifi/sta/Scan.svelte index caa452e..273e9f7 100644 --- a/app/src/routes/wifi/sta/Scan.svelte +++ b/app/src/routes/wifi/sta/Scan.svelte @@ -3,14 +3,14 @@ import { fly } from 'svelte/transition' import { onMount, onDestroy } from 'svelte' import RssiIndicator from '$lib/components/statusbar/RSSIIndicator.svelte' - import type { NetworkItem, NetworkList } from '$lib/types/models' + import { type WifiNetworkScan, type Response as ProtoResponse } from '$lib/platform_shared/api' import { api } from '$lib/api' import { AP, Network, Reload, Cancel } from '$lib/components/icons' import { modals, exitBeforeEnter, type ModalProps } from 'svelte-modals' let { isOpen, storeNetwork }: ModalProps = $props() - const encryptionType = [ + const encryptionTypes = [ 'Open', 'WEP', 'WPA PSK', @@ -22,7 +22,7 @@ 'WAPI PSK' ] - let listOfNetworks: NetworkItem[] = $state([]) + let listOfNetworks = $state([]) let scanActive = $state(false) @@ -38,13 +38,14 @@ } async function pollingResults() { - const result = await api.get('/api/wifi/networks') + const result = await api.get('/api/wifi/networks') if (result.isErr()) { console.error(`Error occurred while fetching: `, result.inner) return false } - let response = result.inner - listOfNetworks = response.networks + if (result.inner.wifiNetworkList) { + listOfNetworks = result.inner.wifiNetworkList.networks + } scanActive = false if (listOfNetworks.length) { clearInterval(pollingId) @@ -106,7 +107,7 @@
{network.ssid}
- Security: {encryptionType[network.encryption_type]}, + Security: {encryptionTypes[network.encryptionType]}, Channel: {network.channel}
diff --git a/app/src/routes/wifi/sta/Wifi.svelte b/app/src/routes/wifi/sta/Wifi.svelte index e923f72..75df57f 100644 --- a/app/src/routes/wifi/sta/Wifi.svelte +++ b/app/src/routes/wifi/sta/Wifi.svelte @@ -10,8 +10,13 @@ import ScanNetworks from './Scan.svelte' import Spinner from '$lib/components/Spinner.svelte' import InfoDialog from '$lib/components/InfoDialog.svelte' - import { type WifiStatus } from '$lib/types/models' - import { WifiSettings, WifiNetwork, Response, Request } from '$lib/platform_shared/api' + import { + type WifiStatus, + type WifiSettings, + type WifiNetwork, + type Response as ProtoResponse, + Request + } from '$lib/platform_shared/api' import { api } from '$lib/api' import { ipToUint32, uint32ToIp, isValidIpString } from '$lib/utilities' import { @@ -80,17 +85,19 @@ let formErrorhostname = $state(false) async function getWifiStatus() { - const result = await api.get('/api/wifi/sta/status') + const result = await api.get('/api/wifi/sta/status') if (result.isErr()) { console.error(`Error occurred while fetching: `, result.inner) return } - wifiStatus = result.inner + if (result.inner.wifiStatus) { + wifiStatus = result.inner.wifiStatus + } return wifiStatus } async function getWifiSettings() { - const result = await api.get('/api/wifi/sta/settings') + const result = await api.get('/api/wifi/sta/settings') if (result.isErr()) { console.error(`Error occurred while fetching: `, result.inner) return @@ -101,7 +108,7 @@ } async function postWiFiSettings(data: WifiSettings) { - const result = await api.post_proto('/api/wifi/sta/settings', Request.create({ wifiSettings: data })) + const result = await api.post_proto('/api/wifi/sta/settings', Request.create({ wifiSettings: data })) if (result.isErr()) { console.error(`Error occurred while fetching: `, result.inner) notifications.error('User not authorized.', 3000) @@ -330,7 +337,7 @@ @@ -361,7 +368,7 @@ {/if} diff --git a/esp32/include/wifi_service.h b/esp32/include/wifi_service.h index 2942846..1678e26 100644 --- a/esp32/include/wifi_service.h +++ b/esp32/include/wifi_service.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -17,8 +16,6 @@ class WiFiService : public StatefulService { private: - static void getNetworks(JsonObject &root); - static void getNetworkStatus(JsonObject &root); void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info); static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); diff --git a/esp32/src/wifi_service.cpp b/esp32/src/wifi_service.cpp index 70cd949..4996543 100644 --- a/esp32/src/wifi_service.cpp +++ b/esp32/src/wifi_service.cpp @@ -60,10 +60,23 @@ esp_err_t WiFiService::getNetworks(httpd_req_t *request) { return handleScan(request); } - JsonDocument doc; - JsonObject root = doc.to(); - getNetworks(root); - return WebServer::sendJson(request, 200, doc); + api_Response response = api_Response_init_zero; + response.which_payload = api_Response_wifi_network_list_tag; + api_WifiNetworkList &networkList = response.payload.wifi_network_list; + + // Limit to max_count from options file (20) + size_t count = (numNetworks > 20) ? 20 : static_cast(numNetworks); + networkList.networks_count = count; + + for (size_t i = 0; i < count; i++) { + networkList.networks[i].rssi = WiFi.RSSI(i); + strncpy(networkList.networks[i].ssid, WiFi.SSID(i).c_str(), sizeof(networkList.networks[i].ssid) - 1); + strncpy(networkList.networks[i].bssid, WiFi.BSSIDstr(i).c_str(), sizeof(networkList.networks[i].bssid) - 1); + networkList.networks[i].channel = WiFi.channel(i); + networkList.networks[i].encryption_type = static_cast(WiFi.encryptionType(i)); + } + + return WebServer::sendProto(request, 200, api_Response_fields, &response, api_Response_size); } void WiFiService::setupMDNS(const char *hostname) { @@ -74,47 +87,35 @@ void WiFiService::setupMDNS(const char *hostname) { MDNS.addServiceTxt("http", "tcp", "Firmware Version", APP_VERSION); } -void WiFiService::getNetworks(JsonObject &root) { - JsonArray networks = root["networks"].to(); - int numNetworks = WiFi.scanComplete(); - for (int i = 0; i < numNetworks; i++) { - JsonObject network = networks.add(); - network["rssi"] = WiFi.RSSI(i); - network["ssid"] = WiFi.SSID(i); - network["bssid"] = WiFi.BSSIDstr(i); - network["channel"] = WiFi.channel(i); - network["encryption_type"] = (uint8_t)WiFi.encryptionType(i); - } -} - esp_err_t WiFiService::getNetworkStatus(httpd_req_t *request) { - JsonDocument doc; - JsonObject root = doc.to(); - getNetworkStatus(root); - return WebServer::sendJson(request, 200, doc); -} + api_Response response = api_Response_init_zero; + response.which_payload = api_Response_wifi_status_tag; + api_WifiStatus &wifiStatus = response.payload.wifi_status; -void WiFiService::getNetworkStatus(JsonObject &root) { wl_status_t status = WiFi.status(); - root["status"] = (uint8_t)status; + wifiStatus.status = static_cast(status); + if (status == WL_CONNECTED) { - root["local_ip"] = (uint32_t)(WiFi.localIP()); - root["mac_address"] = WiFi.macAddress(); - root["rssi"] = WiFi.RSSI(); - root["ssid"] = WiFi.SSID(); - root["bssid"] = WiFi.BSSIDstr(); - root["channel"] = WiFi.channel(); - root["subnet_mask"] = (uint32_t)(WiFi.subnetMask()); - root["gateway_ip"] = (uint32_t)(WiFi.gatewayIP()); + wifiStatus.local_ip = static_cast(WiFi.localIP()); + strncpy(wifiStatus.mac_address, WiFi.macAddress().c_str(), sizeof(wifiStatus.mac_address) - 1); + wifiStatus.rssi = WiFi.RSSI(); + strncpy(wifiStatus.ssid, WiFi.SSID().c_str(), sizeof(wifiStatus.ssid) - 1); + strncpy(wifiStatus.bssid, WiFi.BSSIDstr().c_str(), sizeof(wifiStatus.bssid) - 1); + wifiStatus.channel = WiFi.channel(); + wifiStatus.subnet_mask = static_cast(WiFi.subnetMask()); + wifiStatus.gateway_ip = static_cast(WiFi.gatewayIP()); + IPAddress dnsIP1 = WiFi.dnsIP(0); IPAddress dnsIP2 = WiFi.dnsIP(1); if (dnsIP1 != IPAddress(0, 0, 0, 0)) { - root["dns_ip_1"] = (uint32_t)(dnsIP1); + wifiStatus.dns_ip_1 = static_cast(dnsIP1); } if (dnsIP2 != IPAddress(0, 0, 0, 0)) { - root["dns_ip_2"] = (uint32_t)(dnsIP2); + wifiStatus.dns_ip_2 = static_cast(dnsIP2); } } + + return WebServer::sendProto(request, 200, api_Response_fields, &response, api_Response_size); } void WiFiService::manageSTA() { diff --git a/platform_shared/api.options b/platform_shared/api.options index 371e076..9da0aeb 100644 --- a/platform_shared/api.options +++ b/platform_shared/api.options @@ -24,6 +24,14 @@ api.WifiNetwork.password max_size:65 api.WifiSettings.hostname max_size:33 api.WifiSettings.wifi_networks max_count:5 +api.WifiNetworkScan.ssid max_size:33 +api.WifiNetworkScan.bssid max_size:18 +api.WifiNetworkList.networks max_count:20 + +api.WifiStatus.mac_address max_size:18 +api.WifiStatus.ssid max_size:33 +api.WifiStatus.bssid max_size:18 + api.MDNSTxtRecord.key max_size:32 api.MDNSTxtRecord.value max_size:64 diff --git a/platform_shared/api.proto b/platform_shared/api.proto index e479844..a6ced33 100644 --- a/platform_shared/api.proto +++ b/platform_shared/api.proto @@ -86,6 +86,35 @@ message WifiSettings { message WifiSettingsRequest {} +// WiFi scan result - single network found during scan +message WifiNetworkScan { + int32 rssi = 1; + string ssid = 2; + string bssid = 3; + uint32 channel = 4; + uint32 encryption_type = 5; +} + +// Response for /api/wifi/networks endpoint +message WifiNetworkList { + repeated WifiNetworkScan networks = 1; +} + +// Response for /api/wifi/sta/status endpoint +message WifiStatus { + uint32 status = 1; + uint32 local_ip = 2; + string mac_address = 3; + int32 rssi = 4; + string ssid = 5; + string bssid = 6; + uint32 channel = 7; + uint32 subnet_mask = 8; + uint32 gateway_ip = 9; + uint32 dns_ip_1 = 10; + uint32 dns_ip_2 = 11; +} + // ============================================================================= // Camera Settings - shared data types // ============================================================================= @@ -265,6 +294,8 @@ message Response { ServoSettings servo_settings = 20; FileList file_list = 30; WifiSettings wifi_settings = 40; + WifiNetworkList wifi_network_list = 41; + WifiStatus wifi_status = 42; CameraSettings camera_settings = 50; MDNSSettings mdns_settings = 60; MDNSStatus mdns_status = 61;