Skip to content

Commit 0f2ec25

Browse files
authored
Merge pull request #109 from lucasnz/master
soft AP updates
2 parents 204bbf1 + b87d9d6 commit 0f2ec25

9 files changed

Lines changed: 124 additions & 25 deletions

File tree

data/www/espa.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,13 @@ function loadConfig() {
190190
.then(response => response.json())
191191
.then(data => {
192192
document.getElementById('spaName').value = data.spaName;
193+
document.getElementById('softAPPassword').value = data.softAPPassword;
194+
document.getElementById('softAPAlwaysOn').checked = data.softAPAlwaysOn
193195
document.getElementById('mqttServer').value = data.mqttServer;
194196
document.getElementById('mqttPort').value = data.mqttPort;
195197
document.getElementById('mqttUsername').value = data.mqttUsername;
196198
document.getElementById('mqttPassword').value = data.mqttPassword;
197-
document.getElementById('updateFrequency').value = data.updateFrequency;
199+
document.getElementById('spaPollFrequency').value = data.spaPollFrequency;
198200

199201
// Enable form fields and save button
200202
$('#config_form input').prop('disabled', false);

data/www/index.htm

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,17 @@ <h5 class="modal-title" id="configModalTitle">Change Settings</h5>
194194
</div>
195195
<form id="config_form" action='#' method='POST'>
196196
<div class="mb-3">
197-
<label for="spaName">Spa Name</label>
197+
<label for="spaName">Spa Name (also used for AP SSID)</label>
198198
<input type='text' class="form-control" name='spaName' id='spaName'>
199199
</div>
200+
<div class="mb-3">
201+
<label for="softAPPassword">Soft AP Password</label>
202+
<input type='text' class="form-control" name='softAPPassword' id='softAPPassword'>
203+
</div>
204+
<div class="mb-3">
205+
<label for="softAPAlwaysOn">AP Always On</label>
206+
<input type='checkbox' class="form-check-input" name='softAPAlwaysOn' id='softAPAlwaysOn'>
207+
</div>
200208
<div class="mb-3">
201209
<label for="mqttServer">MQTT Server</label>
202210
<input type='text' class="form-control" name='mqttServer' id='mqttServer'>
@@ -214,8 +222,8 @@ <h5 class="modal-title" id="configModalTitle">Change Settings</h5>
214222
<input type='text' class="form-control" name='mqttPassword' id='mqttPassword'>
215223
</div>
216224
<div class="mb-3">
217-
<label for="updateFrequency">Poll Frequency (seconds)</label>
218-
<input type='number' class="form-control" name='updateFrequency' id='updateFrequency' step="1" min="10" max="300">
225+
<label for="spaPollFrequency">Spa Poll Frequency (seconds)</label>
226+
<input type='number' class="form-control" name='spaPollFrequency' id='spaPollFrequency' step="1" min="10" max="300">
219227
</div>
220228
</form>
221229
</div>

get_version.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ def get_git_version():
3333

3434
return version
3535

36+
build_info = get_git_version()
3637
# Append the version to build flags
37-
env.Append(CPPDEFINES=[("BUILD_INFO", f'"{get_git_version()}"')])
38+
env.Append(CPPDEFINES=[("BUILD_INFO", f'"{build_info}"')])
3839
env.Append(CPPDEFINES=[("PIOENV", f'"{env["PIOENV"]}"')])
40+
41+
# Output the values to the console
42+
print(f"BUILD_INFO: {build_info}")
43+
print(f"PIOENV: {env['PIOENV']}")

lib/Config/Config.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ bool Config::readConfig() {
2222
MqttUsername.setValue(preferences.getString("MqttUsername", ""));
2323
MqttPassword.setValue(preferences.getString("MqttPassword", ""));
2424
SpaName.setValue(preferences.getString("SpaName", "eSpa"));
25-
UpdateFrequency.setValue(preferences.getInt("spaPollFreq", 60));
25+
SpaPollFrequency.setValue(preferences.getInt("spaPollFreq", 60));
26+
SoftAPAlwaysOn.setValue(preferences.getBool("SoftAPAlwaysOn", true));
27+
SoftAPPassword.setValue(preferences.getString("SoftAPPassword", "eSPA-Password"));
2628

2729
preferences.end();
2830
return true;
@@ -41,7 +43,9 @@ void Config::writeConfig() {
4143
preferences.putString("MqttUsername", MqttUsername.getValue());
4244
preferences.putString("MqttPassword", MqttPassword.getValue());
4345
preferences.putString("SpaName", SpaName.getValue());
44-
preferences.putInt("spaPollFreq", UpdateFrequency.getValue());
46+
preferences.putInt("spaPollFreq", SpaPollFrequency.getValue());
47+
preferences.putBool("SoftAPAlwaysOn", SoftAPAlwaysOn.getValue());
48+
preferences.putString("SoftAPPassword", SoftAPPassword.getValue());
4549
preferences.end();
4650
} else {
4751
debugE("Failed to open Preferences for writing");

lib/Config/Config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ class ControllerConfig {
6969
Setting<String> MqttUsername = Setting<String>("MqttUsername");
7070
Setting<String> MqttPassword = Setting<String>("MqttPassword");
7171
Setting<String> SpaName = Setting<String>("SpaName", "eSpa");
72-
Setting<int> UpdateFrequency = Setting<int>("UpdateFrequency", 60, 10, 300);
72+
Setting<int> SpaPollFrequency = Setting<int>("SpaPollFrequency", 60, 10, 300);
73+
Setting<bool> SoftAPAlwaysOn = Setting<bool>("SoftAPAlwaysOn", true);
74+
Setting<String> SoftAPPassword = Setting<String>("SoftAPPassword", "eSPA-Password");
7375
};
7476

7577
class Config : public ControllerConfig {

lib/SpaInterface/SpaInterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ SpaInterface::SpaInterface() : port(SPA_SERIAL) {
1212
SpaInterface::~SpaInterface() {}
1313

1414

15-
void SpaInterface::setUpdateFrequency(int updateFrequency) {
15+
void SpaInterface::setSpaPollFrequency(int updateFrequency) {
1616
_updateFrequency = updateFrequency;
1717
}
1818

lib/SpaInterface/SpaInterface.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ class SpaInterface : public SpaProperties {
115115
~SpaInterface();
116116

117117
/// @brief configure how often the spa is polled in seconds.
118-
/// @param updateFrequency
119-
void setUpdateFrequency(int updateFrequency);
118+
/// @param SpaPollFrequency
119+
void setSpaPollFrequency(int updateFrequency);
120120

121121
/// @brief Complete RF command response in a single string
122122
Property<String> statusResponse;

lib/WebUI/WebUI.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,14 @@ void WebUI::begin() {
8484
server.on("/config", HTTP_POST, [this](AsyncWebServerRequest *request) {
8585
debugD("uri: %s", request->url().c_str());
8686
if (request->hasParam("spaName", true)) _config->SpaName.setValue(request->getParam("spaName", true)->value());
87+
if (request->hasParam("softAPAlwaysOn", true)) _config->SoftAPAlwaysOn.setValue(true);
88+
else _config->SoftAPAlwaysOn.setValue(false); // Default to false if not provided
89+
if (request->hasParam("softAPPassword", true)) _config->SoftAPPassword.setValue(request->getParam("softAPPassword", true)->value());
8790
if (request->hasParam("mqttServer", true)) _config->MqttServer.setValue(request->getParam("mqttServer", true)->value());
8891
if (request->hasParam("mqttPort", true)) _config->MqttPort.setValue(request->getParam("mqttPort", true)->value().toInt());
8992
if (request->hasParam("mqttUsername", true)) _config->MqttUsername.setValue(request->getParam("mqttUsername", true)->value());
9093
if (request->hasParam("mqttPassword", true)) _config->MqttPassword.setValue(request->getParam("mqttPassword", true)->value());
91-
if (request->hasParam("updateFrequency", true)) _config->UpdateFrequency.setValue(request->getParam("updateFrequency", true)->value().toInt());
94+
if (request->hasParam("spaPollFrequency", true)) _config->SpaPollFrequency.setValue(request->getParam("spaPollFrequency", true)->value().toInt());
9295
_config->writeConfig();
9396
AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Updated");
9497
response->addHeader("Connection", "close");
@@ -99,11 +102,13 @@ void WebUI::begin() {
99102
debugD("uri: %s", request->url().c_str());
100103
String configJson = "{";
101104
configJson += "\"spaName\":\"" + _config->SpaName.getValue() + "\",";
105+
configJson += "\"softAPAlwaysOn\":" + String(_config->SoftAPAlwaysOn.getValue() ? "true" : "false") + ",";
106+
configJson += "\"softAPPassword\":\"" + _config->SoftAPPassword.getValue() + "\",";
102107
configJson += "\"mqttServer\":\"" + _config->MqttServer.getValue() + "\",";
103108
configJson += "\"mqttPort\":\"" + String(_config->MqttPort.getValue()) + "\",";
104109
configJson += "\"mqttUsername\":\"" + _config->MqttUsername.getValue() + "\",";
105110
configJson += "\"mqttPassword\":\"" + _config->MqttPassword.getValue() + "\",";
106-
configJson += "\"updateFrequency\":" + String(_config->UpdateFrequency.getValue());
111+
configJson += "\"spaPollFrequency\":" + String(_config->SpaPollFrequency.getValue());
107112
configJson += "}";
108113
AsyncWebServerResponse *response = request->beginResponse(200, "application/json", configJson);
109114
response->addHeader("Connection", "close");

src/main.cpp

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ ulong bootTime = millis();
4545
ulong statusLastPublish = millis();
4646
bool delayedStart = true; // Delay spa connection for 10sec after boot to allow for external debugging if required.
4747
bool autoDiscoveryPublished = false;
48+
bool wifiRestoredFlag = true; // Flag to indicate if Wi-Fi has been restored after a disconnect.
4849

4950
String mqttBase = "";
5051
String mqttStatusTopic = "";
@@ -57,6 +58,8 @@ String spaSerialNumber = "";
5758
/// @brief Flag to indicate that the mqtt configuration has changed and therefore the MQTT
5859
/// client needs to be restarted.
5960
bool updateMqtt = false;
61+
/// @brief Flag to indicate that the Wi-Fi configuration has changed and therefore the Wi-Fi
62+
bool updateSoftAP = false;
6063
bool setSpaCallbackReady = false;
6164
String spaCallbackProperty;
6265
String spaCallbackValue;
@@ -136,11 +139,17 @@ void configChangeCallbackString(const char* name, String value) {
136139
else if (strcmp(name, "MqttPassword") == 0) updateMqtt = true;
137140
else if (strcmp(name, "SpaName") == 0) { } //TODO - Changing the SpaName currently requires the user to:
138141
// delete the entities in MQTT then reboot the ESP
142+
else if (strcmp(name, "SoftAPPassword") == 0) updateSoftAP = true;
139143
}
140144

141145
void configChangeCallbackInt(const char* name, int value) {
142146
debugD("%s: %i", name, value);
143-
if (strcmp(name, "UpdateFrequency") == 0) si.setUpdateFrequency(value);
147+
if (strcmp(name, "SpaPollFrequency") == 0) si.setSpaPollFrequency(value);
148+
}
149+
150+
void configChangeCallbackBool(const char* name, bool value) {
151+
debugD("%s: %s", name, value ? "true" : "false");
152+
if (strcmp(name, "SoftAPAlwaysOn") == 0) updateSoftAP = true;
144153
}
145154

146155
void mqttHaAutoDiscovery() {
@@ -570,6 +579,23 @@ String sanitizeHostname(const String& input) {
570579
return sanitized;
571580
}
572581

582+
void wifiRestored() {
583+
debugI("Wi-Fi connection restored");
584+
wifiRestoredFlag = true;
585+
586+
if (!config.SoftAPAlwaysOn.getValue()) {
587+
WiFi.softAPdisconnect(true); // Disable AP mode if reconnected
588+
WiFi.mode(WIFI_STA);
589+
}
590+
MDNS.end(); // Stop mDNS responder (if it was running)
591+
if (!MDNS.begin(WiFi.getHostname())) {
592+
debugE("Failed to start mDNS responder");
593+
} else {
594+
debugI("mDNS responder restarted");
595+
}
596+
597+
}
598+
573599
#pragma endregion
574600

575601
void setup() {
@@ -600,9 +626,31 @@ void setup() {
600626
blinker.setState(STATE_WIFI_NOT_CONNECTED);
601627
WiFi.setHostname(sanitizeHostname(config.SpaName.getValue()).c_str());
602628

603-
WiFi.mode(WIFI_AP_STA);
629+
if (config.SoftAPAlwaysOn.getValue()) {
630+
WiFi.mode(WIFI_AP_STA);
631+
WiFi.softAP(WiFi.getHostname(), config.SoftAPPassword.getValue().c_str());
632+
} else {
633+
WiFi.mode(WIFI_STA);
634+
}
635+
636+
//WiFi.begin(config.WiFiSSID.getValue().c_str(), config.WiFiPassword.getValue().c_str());
604637
WiFi.begin();
605-
WiFi.softAP(WiFi.getHostname(), "eSPA-Password"); // Start the AP with the hostname and a default password
638+
if (WiFi.waitForConnectResult() == WL_CONNECTED) {
639+
debugI("Connected to Wi-Fi as %s", WiFi.getHostname());
640+
int totalTry = 5;
641+
while (!MDNS.begin(WiFi.getHostname()) && totalTry > 0) {
642+
debugW(".");
643+
delay(1000);
644+
totalTry--;
645+
}
646+
debugA("mDNS responder started");
647+
} else {
648+
debugW("Failed to connect to Wi-Fi, starting AP mode");
649+
if (!config.SoftAPAlwaysOn.getValue()) {
650+
WiFi.mode(WIFI_AP_STA);
651+
WiFi.softAP(WiFi.getHostname(), config.SoftAPPassword.getValue().c_str());
652+
}
653+
}
606654

607655
Debug.begin(WiFi.getHostname()); // Hostname seems to be for display purposes only, no functional impact.
608656
Debug.setResetCmdEnabled(true); // This seems to be not needed to be in Setup.
@@ -618,10 +666,11 @@ void setup() {
618666

619667
ui.setWifiManagerCallback(startWifiManagerCallback);
620668
ui.setSpaCallback(setSpaCallback);
621-
si.setUpdateFrequency(config.UpdateFrequency.getValue());
669+
si.setSpaPollFrequency(config.SpaPollFrequency.getValue());
622670

623671
config.setCallback(configChangeCallbackString);
624672
config.setCallback(configChangeCallbackInt);
673+
config.setCallback(configChangeCallbackBool);
625674

626675
}
627676

@@ -639,23 +688,32 @@ void loop() {
639688

640689
if (WiFi.status() != WL_CONNECTED) {
641690
blinker.setState(STATE_WIFI_NOT_CONNECTED);
691+
wifiRestoredFlag = false;
642692

643-
if (millis()-wifiLastConnect > 1000) { // Reconnect every second if not connected
693+
if (millis() - wifiLastConnect > 10000) { // Reconnect every 10 seconds if not connected
644694
debugI("Wifi reconnecting...");
645695
wifiLastConnect = millis();
646-
if (WiFi.reconnect()) {
696+
WiFi.disconnect();
697+
delay(100); // Short delay to ensure disconnect
698+
WiFi.begin();
699+
if (WiFi.waitForConnectResult() == WL_CONNECTED) {
647700
debugI("Wifi reconnected");
648-
MDNS.end(); // Stop mDNS responder (if it was running)
649-
if (!MDNS.begin(WiFi.getHostname())) {
650-
debugE("Failed to start mDNS responder");
651-
} else {
652-
debugI("mDNS responder restarted");
653-
}
701+
wifiRestored();
654702
} else {
655703
debugW("Wifi reconnect failed");
704+
if (WiFi.getMode() == WIFI_STA && !config.SoftAPAlwaysOn.getValue()) {
705+
debugW("Failed to connect to Wi-Fi, starting AP mode");
706+
WiFi.mode(WIFI_AP_STA);
707+
WiFi.softAP(WiFi.getHostname(), config.SoftAPPassword.getValue().c_str()); // Start the AP with the hostname and password
708+
} else {
709+
debugE("Failed to connect to Wi-Fi, but already in AP mode");
710+
}
656711
};
657712
}
658713
} else {
714+
if (!wifiRestoredFlag) {
715+
wifiRestored();
716+
}
659717
if (delayedStart) {
660718
delayedStart = !(bootTime + 10000 < millis());
661719
} else {
@@ -725,5 +783,20 @@ void loop() {
725783
updateMqtt = false;
726784
}
727785

786+
if (updateSoftAP) {
787+
debugD("Changing SoftAP settings...");
788+
789+
if (config.SoftAPAlwaysOn.getValue()) {
790+
WiFi.mode(WIFI_AP_STA);
791+
WiFi.softAP(config.SpaName.getValue().c_str(), config.SoftAPPassword.getValue().c_str());
792+
debugI("Soft AP enabled");
793+
} else {
794+
WiFi.softAPdisconnect(true);
795+
WiFi.mode(WIFI_STA);
796+
debugI("Soft AP disabled");
797+
}
798+
updateSoftAP = false;
799+
}
800+
728801
mqttClient.loop();
729802
}

0 commit comments

Comments
 (0)