mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-09 14:11:39 +02:00
0.8.45
* start implementing a wizard for initial (WiFi) configuration #1199
This commit is contained in:
parent
617cf0a92a
commit
5ca26895a1
9 changed files with 158 additions and 9 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
## 0.8.45 - 2024-01-05
|
## 0.8.45 - 2024-01-05
|
||||||
* fix MqTT total values #1326
|
* fix MqTT total values #1326
|
||||||
|
* start implementing a wizard for initial (WiFi) configuration #1199
|
||||||
|
|
||||||
## 0.8.44 - 2024-01-05
|
## 0.8.44 - 2024-01-05
|
||||||
* fix MqTT transmission of data #1326
|
* fix MqTT transmission of data #1326
|
||||||
|
|
12
src/app.h
12
src/app.h
|
@ -150,6 +150,18 @@ class app : public IApp, public ah::Scheduler {
|
||||||
return mWifi.getAvailNetworks(obj);
|
return mWifi.getAvailNetworks(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setupStation(void) {
|
||||||
|
mWifi.setupStation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStopApAllowedMode(bool allowed) {
|
||||||
|
mWifi.setStopApAllowedMode(allowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getStationIp(void) {
|
||||||
|
return mWifi.getStationIp();
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !defined(ETHERNET) */
|
#endif /* !defined(ETHERNET) */
|
||||||
|
|
||||||
void setRebootFlag() {
|
void setRebootFlag() {
|
||||||
|
|
|
@ -37,6 +37,9 @@ class IApp {
|
||||||
#if !defined(ETHERNET)
|
#if !defined(ETHERNET)
|
||||||
virtual void scanAvailNetworks() = 0;
|
virtual void scanAvailNetworks() = 0;
|
||||||
virtual bool getAvailNetworks(JsonObject obj) = 0;
|
virtual bool getAvailNetworks(JsonObject obj) = 0;
|
||||||
|
virtual void setupStation(void) = 0;
|
||||||
|
virtual void setStopApAllowedMode(bool allowed) = 0;
|
||||||
|
virtual String getStationIp(void) = 0;
|
||||||
#endif /* defined(ETHERNET) */
|
#endif /* defined(ETHERNET) */
|
||||||
|
|
||||||
virtual uint32_t getUptime() = 0;
|
virtual uint32_t getUptime() = 0;
|
||||||
|
|
|
@ -100,6 +100,7 @@ class RestApi {
|
||||||
else if(path == "setup") getSetup(request, root);
|
else if(path == "setup") getSetup(request, root);
|
||||||
#if !defined(ETHERNET)
|
#if !defined(ETHERNET)
|
||||||
else if(path == "setup/networks") getNetworks(root);
|
else if(path == "setup/networks") getNetworks(root);
|
||||||
|
else if(path == "setup/getip") getWifiIp(root);
|
||||||
#endif /* !defined(ETHERNET) */
|
#endif /* !defined(ETHERNET) */
|
||||||
else if(path == "live") getLive(request,root);
|
else if(path == "live") getLive(request,root);
|
||||||
else {
|
else {
|
||||||
|
@ -754,6 +755,9 @@ class RestApi {
|
||||||
void getNetworks(JsonObject obj) {
|
void getNetworks(JsonObject obj) {
|
||||||
mApp->getAvailNetworks(obj);
|
mApp->getAvailNetworks(obj);
|
||||||
}
|
}
|
||||||
|
void getWifiIp(JsonObject obj) {
|
||||||
|
obj[F("ip")] = mApp->getStationIp();
|
||||||
|
}
|
||||||
#endif /* !defined(ETHERNET) */
|
#endif /* !defined(ETHERNET) */
|
||||||
|
|
||||||
void getLive(AsyncWebServerRequest *request, JsonObject obj) {
|
void getLive(AsyncWebServerRequest *request, JsonObject obj) {
|
||||||
|
@ -834,7 +838,13 @@ class RestApi {
|
||||||
mTimezoneOffset = jsonIn[F("val")];
|
mTimezoneOffset = jsonIn[F("val")];
|
||||||
else if(F("discovery_cfg") == jsonIn[F("cmd")])
|
else if(F("discovery_cfg") == jsonIn[F("cmd")])
|
||||||
mApp->setMqttDiscoveryFlag(); // for homeassistant
|
mApp->setMqttDiscoveryFlag(); // for homeassistant
|
||||||
else if(F("save_iv") == jsonIn[F("cmd")]) {
|
else if(F("save_wifi") == jsonIn[F("cmd")]) {
|
||||||
|
snprintf(mConfig->sys.stationSsid, SSID_LEN, "%s", jsonIn[F("ssid")].as<const char*>());
|
||||||
|
snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", jsonIn[F("pwd")].as<const char*>());
|
||||||
|
mApp->saveSettings(false); // without reboot
|
||||||
|
mApp->setStopApAllowedMode(false);
|
||||||
|
mApp->setupStation();
|
||||||
|
} else if(F("save_iv") == jsonIn[F("cmd")]) {
|
||||||
Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")], false);
|
Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")], false);
|
||||||
iv->config->enabled = jsonIn[F("en")];
|
iv->config->enabled = jsonIn[F("en")];
|
||||||
iv->config->serial.u64 = jsonIn[F("ser")];
|
iv->config->serial.u64 = jsonIn[F("ser")];
|
||||||
|
|
|
@ -814,3 +814,20 @@ ul {
|
||||||
background-color: var(--input-bg);
|
background-color: var(--input-bg);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.d-flex {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jc {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aic {
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
87
src/web/html/wizard.html
Normal file
87
src/web/html/wizard.html
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Setup Wizard</title>
|
||||||
|
{#HTML_HEADER}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div class="container d-flex aic jc">
|
||||||
|
<div id="con"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var v;
|
||||||
|
var found = false;
|
||||||
|
var c = document.getElementById("con");
|
||||||
|
|
||||||
|
function sect(e1, e2) {
|
||||||
|
return ml("div", {class: "row"}, [
|
||||||
|
ml("div", {class: "col-12"}, ml("p", {}, e1)),
|
||||||
|
ml("div", {class: "col-12"}, e2)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function wifi() {
|
||||||
|
return ml("div", {}, [
|
||||||
|
ml("div", {class: "row my-5"}, ml("div", {class: "col"}, ml("span", {class: "fs-1"}, "Welcome to AhoyDTU"))),
|
||||||
|
ml("div", {class: "row"}, ml("div", {class: "col"}, ml("span", {class: "fs-5"}, "Network Setup"))),
|
||||||
|
sect("Choose your WiFi Network", ml("select", {id: "net", onchange: () => {if(found) clearInterval(v)}}, ml("option", {value: "-1"}, "---"))),
|
||||||
|
sect("... or name it manually", ml("input", {id: "man", type: "text"})),
|
||||||
|
sect("WiFi Password", ml("input", {id: "pwd", type: "password"})),
|
||||||
|
ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn", value: "next", onclick: () => {saveWifi()}}, null))),
|
||||||
|
ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {href: "http://192.168.4.1/"}, "stop wizard")))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkWifi() {
|
||||||
|
c.replaceChildren(
|
||||||
|
ml("div", {class: "row my-5"}, ml("div", {class: "col"}, ml("span", {class: "fs-1"}, "Welcome to AhoyDTU"))),
|
||||||
|
ml("div", {class: "row"}, ml("div", {class: "col"}, ml("span", {class: "fs-5"}, "Test Connection"))),
|
||||||
|
sect("AhoyDTU is trying to connect to your WiFi", ml("span", {id: "state"}, "connecting ...")),
|
||||||
|
ml("div", {class: "row my-4"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", class:"btn hide", id: "btn", value: "Finish", onclick: () => {redirect()}}, null))),
|
||||||
|
ml("div", {class: "row mt-5"}, ml("div", {class: "col a-c"}, ml("a", {href: "http://192.168.4.1/"}, "stop wizard")))
|
||||||
|
)
|
||||||
|
v = setInterval(() => {getAjax('/api/setup/getip', printIp)}, 2500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirect() {
|
||||||
|
window.location.replace("http://192.168.4.1/")
|
||||||
|
}
|
||||||
|
|
||||||
|
function printIp(obj) {
|
||||||
|
if("0.0.0.0" != obj["ip"]) {
|
||||||
|
clearInterval(v)
|
||||||
|
setHide("btn", false)
|
||||||
|
document.getElementById("state").innerHTML = "success, got following IP in your network: " + obj.ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveWifi() {
|
||||||
|
var ssid = document.getElementById("net").value;
|
||||||
|
if(-1 == ssid)
|
||||||
|
ssid = document.getElementById("man").value;
|
||||||
|
getAjax("/api/setup", ((o) => {if(!o.error) checkWifi()}), "POST", JSON.stringify({cmd: "save_wifi", ssid: ssid, pwd: document.getElementById("pwd").value}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function nets(obj) {
|
||||||
|
var e = document.getElementById("net");
|
||||||
|
if(obj.networks.length > 0) {
|
||||||
|
var a = []
|
||||||
|
a.push(ml("option", {value: -1}, obj.networks.length + " Network(s) found"))
|
||||||
|
for(n of obj.networks) {
|
||||||
|
a.push(ml("option", {value: n.ssid}, n.ssid + " (" + n.rssi + "dBm)"))
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
e.replaceChildren(...a)
|
||||||
|
}
|
||||||
|
getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify({cmd: "scan_wifi"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
getAjax("/api/setup", ((o) => {}), "POST", JSON.stringify({cmd: "scan_wifi"}));
|
||||||
|
c.append(wifi())
|
||||||
|
|
||||||
|
v = setInterval(() => {getAjax('/api/setup/networks', nets)}, 2500);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -36,6 +36,7 @@
|
||||||
#include "html/h/update_html.h"
|
#include "html/h/update_html.h"
|
||||||
#include "html/h/visualization_html.h"
|
#include "html/h/visualization_html.h"
|
||||||
#include "html/h/about_html.h"
|
#include "html/h/about_html.h"
|
||||||
|
#include "html/h/wizard_html.h"
|
||||||
|
|
||||||
#define WEB_SERIAL_BUF_SIZE 2048
|
#define WEB_SERIAL_BUF_SIZE 2048
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ class Web {
|
||||||
mWeb.on("/factorytrue", HTTP_ANY, std::bind(&Web::showHtml, this, std::placeholders::_1));
|
mWeb.on("/factorytrue", HTTP_ANY, std::bind(&Web::showHtml, this, std::placeholders::_1));
|
||||||
|
|
||||||
mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1));
|
mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1));
|
||||||
|
mWeb.on("/wizard", HTTP_GET, std::bind(&Web::onWizard, this, std::placeholders::_1));
|
||||||
mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1));
|
mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1));
|
||||||
|
|
||||||
mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1));
|
mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1));
|
||||||
|
@ -422,7 +424,7 @@ class Web {
|
||||||
|
|
||||||
void showNotFound(AsyncWebServerRequest *request) {
|
void showNotFound(AsyncWebServerRequest *request) {
|
||||||
checkProtection(request);
|
checkProtection(request);
|
||||||
request->redirect("/setup");
|
request->redirect("/wizard");
|
||||||
}
|
}
|
||||||
|
|
||||||
void onReboot(AsyncWebServerRequest *request) {
|
void onReboot(AsyncWebServerRequest *request) {
|
||||||
|
@ -444,6 +446,13 @@ class Web {
|
||||||
getPage(request, PROT_MASK_SETUP, setup_html, setup_html_len);
|
getPage(request, PROT_MASK_SETUP, setup_html, setup_html_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onWizard(AsyncWebServerRequest *request) {
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), wizard_html, wizard_html_len);
|
||||||
|
response->addHeader(F("Content-Encoding"), "gzip");
|
||||||
|
response->addHeader(F("content-type"), "text/html; charset=UTF-8");
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
void showSave(AsyncWebServerRequest *request) {
|
void showSave(AsyncWebServerRequest *request) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("showSave"));
|
DPRINTLN(DBG_VERBOSE, F("showSave"));
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb) {
|
||||||
mCnt = 0;
|
mCnt = 0;
|
||||||
mScanActive = false;
|
mScanActive = false;
|
||||||
mScanCnt = 0;
|
mScanCnt = 0;
|
||||||
|
mStopApAllowed = true;
|
||||||
|
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1));
|
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1));
|
||||||
|
@ -94,7 +95,7 @@ void ahoywifi::tickWifiLoop() {
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
case IN_AP_MODE:
|
case IN_AP_MODE:
|
||||||
if (WiFi.softAPgetStationNum() == 0) {
|
if ((WiFi.softAPgetStationNum() == 0) || (!mStopApAllowed)) {
|
||||||
mCnt = 0;
|
mCnt = 0;
|
||||||
mDns.stop();
|
mDns.stop();
|
||||||
WiFi.mode(WIFI_AP_STA);
|
WiFi.mode(WIFI_AP_STA);
|
||||||
|
@ -105,7 +106,7 @@ void ahoywifi::tickWifiLoop() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DISCONNECTED:
|
case DISCONNECTED:
|
||||||
if (WiFi.softAPgetStationNum() > 0) {
|
if ((WiFi.softAPgetStationNum() > 0) && (mStopApAllowed)) {
|
||||||
mStaConn = IN_AP_MODE;
|
mStaConn = IN_AP_MODE;
|
||||||
// first time switch to AP Mode
|
// first time switch to AP Mode
|
||||||
if (mScanActive) {
|
if (mScanActive) {
|
||||||
|
@ -182,10 +183,12 @@ void ahoywifi::tickWifiLoop() {
|
||||||
break;
|
break;
|
||||||
case GOT_IP:
|
case GOT_IP:
|
||||||
welcome(WiFi.localIP().toString(), F(" (Station)"));
|
welcome(WiFi.localIP().toString(), F(" (Station)"));
|
||||||
|
if(mStopApAllowed) {
|
||||||
WiFi.softAPdisconnect();
|
WiFi.softAPdisconnect();
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
DBGPRINTLN(F("[WiFi] AP disabled"));
|
DBGPRINTLN(F("[WiFi] AP disabled"));
|
||||||
delay(100);
|
delay(100);
|
||||||
|
}
|
||||||
mAppWifiCb(true);
|
mAppWifiCb(true);
|
||||||
mGotDisconnect = false;
|
mGotDisconnect = false;
|
||||||
mStaConn = IN_STA_MODE;
|
mStaConn = IN_STA_MODE;
|
||||||
|
|
|
@ -28,6 +28,13 @@ class ahoywifi {
|
||||||
bool getNtpTime(void);
|
bool getNtpTime(void);
|
||||||
void scanAvailNetworks(void);
|
void scanAvailNetworks(void);
|
||||||
bool getAvailNetworks(JsonObject obj);
|
bool getAvailNetworks(JsonObject obj);
|
||||||
|
void setStopApAllowedMode(bool allowed) {
|
||||||
|
mStopApAllowed = allowed;
|
||||||
|
}
|
||||||
|
String getStationIp(void) {
|
||||||
|
return WiFi.localIP().toString();
|
||||||
|
}
|
||||||
|
void setupStation(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef enum WiFiStatus {
|
typedef enum WiFiStatus {
|
||||||
|
@ -43,7 +50,6 @@ class ahoywifi {
|
||||||
|
|
||||||
void setupWifi(bool startAP);
|
void setupWifi(bool startAP);
|
||||||
void setupAp(void);
|
void setupAp(void);
|
||||||
void setupStation(void);
|
|
||||||
void sendNTPpacket(IPAddress& address);
|
void sendNTPpacket(IPAddress& address);
|
||||||
void sortRSSI(int *sort, int n);
|
void sortRSSI(int *sort, int n);
|
||||||
bool getBSSIDs(void);
|
bool getBSSIDs(void);
|
||||||
|
@ -78,6 +84,7 @@ class ahoywifi {
|
||||||
bool mScanActive;
|
bool mScanActive;
|
||||||
bool mGotDisconnect;
|
bool mGotDisconnect;
|
||||||
std::list<uint8_t> mBSSIDList;
|
std::list<uint8_t> mBSSIDList;
|
||||||
|
bool mStopApAllowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__AHOYWIFI_H__*/
|
#endif /*__AHOYWIFI_H__*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue