Skip to content

Commit c5acd14

Browse files
committed
Feature: support connecting to a fixed Wi-Fi BSSID
1 parent 2f1f0af commit c5acd14

File tree

9 files changed

+84
-2
lines changed

9 files changed

+84
-2
lines changed

include/Configuration.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ struct CONFIG_T {
301301
struct {
302302
char Ssid[WIFI_MAX_SSID_STRLEN + 1];
303303
char Password[WIFI_MAX_PASSWORD_STRLEN + 1];
304+
uint8_t Bssid[6];
304305
uint8_t Ip[4];
305306
uint8_t Netmask[4];
306307
uint8_t Gateway[4];
@@ -449,6 +450,8 @@ class ConfigurationClass {
449450
INVERTER_CONFIG_T* getFreeInverterSlot();
450451
INVERTER_CONFIG_T* getInverterConfig(const uint64_t serial);
451452
void deleteInverterById(const uint8_t id);
453+
String serializeBssid(uint8_t const* bssid);
454+
void deserializeBssid(String const& bssidStr, uint8_t* bssid);
452455

453456
static void serializeHttpRequestConfig(HttpRequestConfig const& source, JsonObject& target);
454457
static void serializeSolarChargerConfig(SolarChargerConfig const& source, JsonObject& target);

include/defaults.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#define WIFI_SSID ""
2020
#define WIFI_PASSWORD ""
21+
#define WIFI_BSSID ""
2122
#define WIFI_DHCP true
2223

2324
#define MDNS_ENABLED false

src/Configuration.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ bool ConfigurationClass::write()
262262
JsonObject wifi = doc["wifi"].to<JsonObject>();
263263
wifi["ssid"] = config.WiFi.Ssid;
264264
wifi["password"] = config.WiFi.Password;
265+
wifi["bssid"] = serializeBssid(config.WiFi.Bssid);
265266
wifi["ip"] = IPAddress(config.WiFi.Ip).toString();
266267
wifi["netmask"] = IPAddress(config.WiFi.Netmask).toString();
267268
wifi["gateway"] = IPAddress(config.WiFi.Gateway).toString();
@@ -673,6 +674,7 @@ bool ConfigurationClass::read()
673674
JsonObject wifi = doc["wifi"];
674675
strlcpy(config.WiFi.Ssid, wifi["ssid"] | WIFI_SSID, sizeof(config.WiFi.Ssid));
675676
strlcpy(config.WiFi.Password, wifi["password"] | WIFI_PASSWORD, sizeof(config.WiFi.Password));
677+
deserializeBssid(wifi["bssid"] | WIFI_BSSID, config.WiFi.Bssid);
676678
strlcpy(config.WiFi.Hostname, wifi["hostname"] | APP_HOSTNAME, sizeof(config.WiFi.Hostname));
677679

678680
IPAddress wifi_ip;
@@ -1175,6 +1177,34 @@ void ConfigurationClass::deleteInverterById(const uint8_t id)
11751177
}
11761178
}
11771179

1180+
String ConfigurationClass::serializeBssid(uint8_t const* bssid)
1181+
{
1182+
if (std::all_of(bssid, bssid + 6, [](uint8_t b) { return b == 0; })) {
1183+
return "";
1184+
}
1185+
1186+
char bssidStr[18];
1187+
snprintf(bssidStr, sizeof(bssidStr), "%02X:%02X:%02X:%02X:%02X:%02X",
1188+
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
1189+
return bssidStr;
1190+
}
1191+
1192+
void ConfigurationClass::deserializeBssid(String const& bssidStr, uint8_t* bssid)
1193+
{
1194+
memset(bssid, 0, 6);
1195+
1196+
String cleanBssidStr = bssidStr;
1197+
cleanBssidStr.replace(":", "");
1198+
cleanBssidStr.replace("-", "");
1199+
1200+
if (cleanBssidStr.length() != 12) { return; }
1201+
1202+
for (int i = 0; i < 6; i++) {
1203+
char byteStr[3] = {cleanBssidStr[i*2], cleanBssidStr[i*2+1], 0};
1204+
bssid[i] = strtol(byteStr, nullptr, 16);
1205+
}
1206+
}
1207+
11781208
void ConfigurationClass::loop()
11791209
{
11801210
std::unique_lock<std::mutex> lock(sWriterMutex);

src/NetworkSettings.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,44 @@ void NetworkSettingsClass::applyConfig()
285285
if (!strcmp(Configuration.get().WiFi.Ssid, "")) {
286286
return;
287287
}
288+
289+
uint8_t const* configuredBssid = NULL; // auto
290+
if (std::any_of(std::begin(Configuration.get().WiFi.Bssid),
291+
std::end(Configuration.get().WiFi.Bssid),
292+
[](uint8_t b) { return b != 0; })) {
293+
configuredBssid = Configuration.get().WiFi.Bssid;
294+
}
295+
296+
auto bssidChanged = [configuredBssid]() -> bool {
297+
uint8_t* currentBssid = WiFi.BSSID();
298+
if (configuredBssid == NULL && currentBssid == NULL) {
299+
return false;
300+
}
301+
302+
if (configuredBssid != NULL || currentBssid != NULL) {
303+
return true;
304+
}
305+
306+
for (int i = 0; i < 6; i++) {
307+
if (configuredBssid[i] != currentBssid[i]) {
308+
return true;
309+
}
310+
}
311+
312+
return false;
313+
};
314+
288315
MessageOutput.print("Configuring WiFi STA using ");
289-
if (strcmp(WiFi.SSID().c_str(), Configuration.get().WiFi.Ssid) || strcmp(WiFi.psk().c_str(), Configuration.get().WiFi.Password)) {
316+
if (strcmp(WiFi.SSID().c_str(), Configuration.get().WiFi.Ssid) ||
317+
strcmp(WiFi.psk().c_str(), Configuration.get().WiFi.Password) ||
318+
bssidChanged()) {
290319
MessageOutput.print("new credentials... ");
320+
291321
WiFi.begin(
292322
Configuration.get().WiFi.Ssid,
293-
Configuration.get().WiFi.Password);
323+
Configuration.get().WiFi.Password,
324+
0, // channel (0 = auto)
325+
configuredBssid);
294326
} else {
295327
MessageOutput.print("existing credentials... ");
296328
WiFi.begin();

src/WebApi_network.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request)
7575
root["dns2"] = IPAddress(config.WiFi.Dns2).toString();
7676
root["ssid"] = config.WiFi.Ssid;
7777
root["password"] = config.WiFi.Password;
78+
root["bssid"] = Configuration.serializeBssid(config.WiFi.Bssid);
7879
root["aptimeout"] = config.WiFi.ApTimeout;
7980
root["mdnsenabled"] = config.Mdns.Enabled;
8081
root["syslogenabled"] = config.Syslog.Enabled;
@@ -100,6 +101,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
100101

101102
if (!(root["ssid"].is<String>()
102103
&& root["password"].is<String>()
104+
&& root["bssid"].is<String>()
103105
&& root["hostname"].is<String>()
104106
&& root["dhcp"].is<bool>()
105107
&& root["ipaddress"].is<String>()
@@ -217,6 +219,7 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
217219
config.WiFi.Dns2[3] = dns2[3];
218220
strlcpy(config.WiFi.Ssid, root["ssid"].as<String>().c_str(), sizeof(config.WiFi.Ssid));
219221
strlcpy(config.WiFi.Password, root["password"].as<String>().c_str(), sizeof(config.WiFi.Password));
222+
Configuration.deserializeBssid(root["bssid"].as<String>(), config.WiFi.Bssid);
220223
strlcpy(config.WiFi.Hostname, root["hostname"].as<String>().c_str(), sizeof(config.WiFi.Hostname));
221224
if (root["dhcp"].as<bool>()) {
222225
config.WiFi.Dhcp = true;

webapp/src/locales/de.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@
531531
"WifiConfiguration": "WLAN-Konfiguration",
532532
"WifiSsid": "WLAN-SSID",
533533
"WifiPassword": "WLAN-Passwort",
534+
"WifiBssid": "WLAN-BSSID",
535+
"WifiBssidHint": "Setze die BSSID des WLAN-Access Points, um mit einem bestimmten Access Point zu verbinden. Leer lassen um jeden Access Point zu erlauben.",
534536
"Hostname": "Hostname",
535537
"HostnameHint": "<b>Hinweis:</b> Der Text <span class=\"font-monospace\">%06X</span> wird durch die letzten 6 Ziffern der ESP-ChipID im Hex-Format ersetzt.",
536538
"EnableDhcp": "DHCP aktivieren",

webapp/src/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,8 @@
533533
"WifiConfiguration": "WiFi Configuration",
534534
"WifiSsid": "WiFi SSID",
535535
"WifiPassword": "WiFi Password",
536+
"WifiBssid": "WiFi BSSID",
537+
"WifiBssidHint": "Set the BSSID of the WiFi Access Point to connect to. Leave empty to allow connecting to any Access Point.",
536538
"Hostname": "Hostname",
537539
"HostnameHint": "<b>Hint:</b> The text <span class=\"font-monospace\">%06X</span> will be replaced with the last 6 digits of the ESP ChipID in hex format.",
538540
"EnableDhcp": "Enable DHCP",

webapp/src/types/NetworkConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export interface NetworkConfig {
22
ssid: string;
33
password: string;
4+
bssid: string;
45
hostname: string;
56
dhcp: boolean;
67
ipaddress: string;

webapp/src/views/NetworkAdminView.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
maxlength="64"
2121
/>
2222

23+
<InputElement
24+
:label="$t('networkadmin.WifiBssid')"
25+
:tooltip="$t('networkadmin.WifiBssidHint')"
26+
v-model="networkConfigList.bssid"
27+
type="text"
28+
maxlength="17"
29+
/>
30+
2331
<InputElement
2432
:label="$t('networkadmin.Hostname')"
2533
v-model="networkConfigList.hostname"

0 commit comments

Comments
 (0)