Updated all wifi endpoints to use protobufs

This commit is contained in:
Niklas Jensen
2026-01-30 18:36:39 +01:00
committed by nikguin04
parent 56d81f75cb
commit 4575f63921
7 changed files with 100 additions and 98 deletions
-43
View File
@@ -17,37 +17,6 @@ export enum MessageTopic {
rssi = 'rssi' 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 vector = { x: number; y: number }
export type GithubRelease = { 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 = { export type Rssi = {
rssi: number rssi: number
ssid: string ssid: string
+8 -7
View File
@@ -3,14 +3,14 @@
import { fly } from 'svelte/transition' import { fly } from 'svelte/transition'
import { onMount, onDestroy } from 'svelte' import { onMount, onDestroy } from 'svelte'
import RssiIndicator from '$lib/components/statusbar/RSSIIndicator.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 { api } from '$lib/api'
import { AP, Network, Reload, Cancel } from '$lib/components/icons' import { AP, Network, Reload, Cancel } from '$lib/components/icons'
import { modals, exitBeforeEnter, type ModalProps } from 'svelte-modals' import { modals, exitBeforeEnter, type ModalProps } from 'svelte-modals'
let { isOpen, storeNetwork }: ModalProps = $props() let { isOpen, storeNetwork }: ModalProps = $props()
const encryptionType = [ const encryptionTypes = [
'Open', 'Open',
'WEP', 'WEP',
'WPA PSK', 'WPA PSK',
@@ -22,7 +22,7 @@
'WAPI PSK' 'WAPI PSK'
] ]
let listOfNetworks: NetworkItem[] = $state([]) let listOfNetworks = $state<WifiNetworkScan[]>([])
let scanActive = $state(false) let scanActive = $state(false)
@@ -38,13 +38,14 @@
} }
async function pollingResults() { async function pollingResults() {
const result = await api.get<NetworkList>('/api/wifi/networks') const result = await api.get<ProtoResponse>('/api/wifi/networks')
if (result.isErr()) { if (result.isErr()) {
console.error(`Error occurred while fetching: `, result.inner) console.error(`Error occurred while fetching: `, result.inner)
return false return false
} }
let response = result.inner if (result.inner.wifiNetworkList) {
listOfNetworks = response.networks listOfNetworks = result.inner.wifiNetworkList.networks
}
scanActive = false scanActive = false
if (listOfNetworks.length) { if (listOfNetworks.length) {
clearInterval(pollingId) clearInterval(pollingId)
@@ -106,7 +107,7 @@
<div> <div>
<div class="font-bold">{network.ssid}</div> <div class="font-bold">{network.ssid}</div>
<div class="text-sm opacity-75"> <div class="text-sm opacity-75">
Security: {encryptionType[network.encryption_type]}, Security: {encryptionTypes[network.encryptionType]},
Channel: {network.channel} Channel: {network.channel}
</div> </div>
</div> </div>
+18 -11
View File
@@ -10,8 +10,13 @@
import ScanNetworks from './Scan.svelte' import ScanNetworks from './Scan.svelte'
import Spinner from '$lib/components/Spinner.svelte' import Spinner from '$lib/components/Spinner.svelte'
import InfoDialog from '$lib/components/InfoDialog.svelte' import InfoDialog from '$lib/components/InfoDialog.svelte'
import { type WifiStatus } from '$lib/types/models' import {
import { WifiSettings, WifiNetwork, Response, Request } from '$lib/platform_shared/api' type WifiStatus,
type WifiSettings,
type WifiNetwork,
type Response as ProtoResponse,
Request
} from '$lib/platform_shared/api'
import { api } from '$lib/api' import { api } from '$lib/api'
import { ipToUint32, uint32ToIp, isValidIpString } from '$lib/utilities' import { ipToUint32, uint32ToIp, isValidIpString } from '$lib/utilities'
import { import {
@@ -80,17 +85,19 @@
let formErrorhostname = $state(false) let formErrorhostname = $state(false)
async function getWifiStatus() { async function getWifiStatus() {
const result = await api.get<WifiStatus>('/api/wifi/sta/status') const result = await api.get<ProtoResponse>('/api/wifi/sta/status')
if (result.isErr()) { if (result.isErr()) {
console.error(`Error occurred while fetching: `, result.inner) console.error(`Error occurred while fetching: `, result.inner)
return return
} }
wifiStatus = result.inner if (result.inner.wifiStatus) {
wifiStatus = result.inner.wifiStatus
}
return wifiStatus return wifiStatus
} }
async function getWifiSettings() { async function getWifiSettings() {
const result = await api.get<Response>('/api/wifi/sta/settings') const result = await api.get<ProtoResponse>('/api/wifi/sta/settings')
if (result.isErr()) { if (result.isErr()) {
console.error(`Error occurred while fetching: `, result.inner) console.error(`Error occurred while fetching: `, result.inner)
return return
@@ -101,7 +108,7 @@
} }
async function postWiFiSettings(data: WifiSettings) { async function postWiFiSettings(data: WifiSettings) {
const result = await api.post_proto<Response>('/api/wifi/sta/settings', Request.create({ wifiSettings: data })) const result = await api.post_proto<ProtoResponse>('/api/wifi/sta/settings', Request.create({ wifiSettings: data }))
if (result.isErr()) { if (result.isErr()) {
console.error(`Error occurred while fetching: `, result.inner) console.error(`Error occurred while fetching: `, result.inner)
notifications.error('User not authorized.', 3000) notifications.error('User not authorized.', 3000)
@@ -330,7 +337,7 @@
<StatusItem <StatusItem
icon={Home} icon={Home}
title="IP Address" title="IP Address"
description={uint32ToIp(wifiStatus.local_ip)} description={uint32ToIp(wifiStatus.localIp)}
/> />
<StatusItem icon={WiFi} title="RSSI" description={`${wifiStatus.rssi} dBm`}> <StatusItem icon={WiFi} title="RSSI" description={`${wifiStatus.rssi} dBm`}>
@@ -361,7 +368,7 @@
<StatusItem <StatusItem
icon={MAC} icon={MAC}
title="MAC Address" title="MAC Address"
description={wifiStatus.mac_address} description={wifiStatus.macAddress}
/> />
<StatusItem <StatusItem
@@ -373,19 +380,19 @@
<StatusItem <StatusItem
icon={Gateway} icon={Gateway}
title="Gateway IP" title="Gateway IP"
description={uint32ToIp(wifiStatus.gateway_ip)} description={uint32ToIp(wifiStatus.gatewayIp)}
/> />
<StatusItem <StatusItem
icon={Subnet} icon={Subnet}
title="Subnet Mask" title="Subnet Mask"
description={uint32ToIp(wifiStatus.subnet_mask)} description={uint32ToIp(wifiStatus.subnetMask)}
/> />
<StatusItem <StatusItem
icon={DNS} icon={DNS}
title="DNS" title="DNS"
description={uint32ToIp(wifiStatus.dns_ip_1)} description={uint32ToIp(wifiStatus.dnsIp1)}
/> />
</div> </div>
{/if} {/if}
-3
View File
@@ -3,7 +3,6 @@
#include <esp_http_server.h> #include <esp_http_server.h>
#include <WiFi.h> #include <WiFi.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <ArduinoJson.h>
#include <string> #include <string>
#include <filesystem.h> #include <filesystem.h>
@@ -17,8 +16,6 @@
class WiFiService : public StatefulService<WiFiSettings> { class WiFiService : public StatefulService<WiFiSettings> {
private: private:
static void getNetworks(JsonObject &root);
static void getNetworkStatus(JsonObject &root);
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info); void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info);
static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
+35 -34
View File
@@ -60,10 +60,23 @@ esp_err_t WiFiService::getNetworks(httpd_req_t *request) {
return handleScan(request); return handleScan(request);
} }
JsonDocument doc; api_Response response = api_Response_init_zero;
JsonObject root = doc.to<JsonObject>(); response.which_payload = api_Response_wifi_network_list_tag;
getNetworks(root); api_WifiNetworkList &networkList = response.payload.wifi_network_list;
return WebServer::sendJson(request, 200, doc);
// Limit to max_count from options file (20)
size_t count = (numNetworks > 20) ? 20 : static_cast<size_t>(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<uint32_t>(WiFi.encryptionType(i));
}
return WebServer::sendProto(request, 200, api_Response_fields, &response, api_Response_size);
} }
void WiFiService::setupMDNS(const char *hostname) { void WiFiService::setupMDNS(const char *hostname) {
@@ -74,47 +87,35 @@ void WiFiService::setupMDNS(const char *hostname) {
MDNS.addServiceTxt("http", "tcp", "Firmware Version", APP_VERSION); MDNS.addServiceTxt("http", "tcp", "Firmware Version", APP_VERSION);
} }
void WiFiService::getNetworks(JsonObject &root) {
JsonArray networks = root["networks"].to<JsonArray>();
int numNetworks = WiFi.scanComplete();
for (int i = 0; i < numNetworks; i++) {
JsonObject network = networks.add<JsonObject>();
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) { esp_err_t WiFiService::getNetworkStatus(httpd_req_t *request) {
JsonDocument doc; api_Response response = api_Response_init_zero;
JsonObject root = doc.to<JsonObject>(); response.which_payload = api_Response_wifi_status_tag;
getNetworkStatus(root); api_WifiStatus &wifiStatus = response.payload.wifi_status;
return WebServer::sendJson(request, 200, doc);
}
void WiFiService::getNetworkStatus(JsonObject &root) {
wl_status_t status = WiFi.status(); wl_status_t status = WiFi.status();
root["status"] = (uint8_t)status; wifiStatus.status = static_cast<uint32_t>(status);
if (status == WL_CONNECTED) { if (status == WL_CONNECTED) {
root["local_ip"] = (uint32_t)(WiFi.localIP()); wifiStatus.local_ip = static_cast<uint32_t>(WiFi.localIP());
root["mac_address"] = WiFi.macAddress(); strncpy(wifiStatus.mac_address, WiFi.macAddress().c_str(), sizeof(wifiStatus.mac_address) - 1);
root["rssi"] = WiFi.RSSI(); wifiStatus.rssi = WiFi.RSSI();
root["ssid"] = WiFi.SSID(); strncpy(wifiStatus.ssid, WiFi.SSID().c_str(), sizeof(wifiStatus.ssid) - 1);
root["bssid"] = WiFi.BSSIDstr(); strncpy(wifiStatus.bssid, WiFi.BSSIDstr().c_str(), sizeof(wifiStatus.bssid) - 1);
root["channel"] = WiFi.channel(); wifiStatus.channel = WiFi.channel();
root["subnet_mask"] = (uint32_t)(WiFi.subnetMask()); wifiStatus.subnet_mask = static_cast<uint32_t>(WiFi.subnetMask());
root["gateway_ip"] = (uint32_t)(WiFi.gatewayIP()); wifiStatus.gateway_ip = static_cast<uint32_t>(WiFi.gatewayIP());
IPAddress dnsIP1 = WiFi.dnsIP(0); IPAddress dnsIP1 = WiFi.dnsIP(0);
IPAddress dnsIP2 = WiFi.dnsIP(1); IPAddress dnsIP2 = WiFi.dnsIP(1);
if (dnsIP1 != IPAddress(0, 0, 0, 0)) { if (dnsIP1 != IPAddress(0, 0, 0, 0)) {
root["dns_ip_1"] = (uint32_t)(dnsIP1); wifiStatus.dns_ip_1 = static_cast<uint32_t>(dnsIP1);
} }
if (dnsIP2 != IPAddress(0, 0, 0, 0)) { if (dnsIP2 != IPAddress(0, 0, 0, 0)) {
root["dns_ip_2"] = (uint32_t)(dnsIP2); wifiStatus.dns_ip_2 = static_cast<uint32_t>(dnsIP2);
} }
} }
return WebServer::sendProto(request, 200, api_Response_fields, &response, api_Response_size);
} }
void WiFiService::manageSTA() { void WiFiService::manageSTA() {
+8
View File
@@ -24,6 +24,14 @@ api.WifiNetwork.password max_size:65
api.WifiSettings.hostname max_size:33 api.WifiSettings.hostname max_size:33
api.WifiSettings.wifi_networks max_count:5 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.key max_size:32
api.MDNSTxtRecord.value max_size:64 api.MDNSTxtRecord.value max_size:64
+31
View File
@@ -86,6 +86,35 @@ message WifiSettings {
message WifiSettingsRequest {} 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 // Camera Settings - shared data types
// ============================================================================= // =============================================================================
@@ -265,6 +294,8 @@ message Response {
ServoSettings servo_settings = 20; ServoSettings servo_settings = 20;
FileList file_list = 30; FileList file_list = 30;
WifiSettings wifi_settings = 40; WifiSettings wifi_settings = 40;
WifiNetworkList wifi_network_list = 41;
WifiStatus wifi_status = 42;
CameraSettings camera_settings = 50; CameraSettings camera_settings = 50;
MDNSSettings mdns_settings = 60; MDNSSettings mdns_settings = 60;
MDNSStatus mdns_status = 61; MDNSStatus mdns_status = 61;