Browse Source

0.8.45

* start implementing a wizard for initial (WiFi) configuration #1199
pull/1328/head
lumapu 9 months ago
parent
commit
5ca26895a1
  1. 1
      src/CHANGES.md
  2. 12
      src/app.h
  3. 3
      src/appInterface.h
  4. 12
      src/web/RestApi.h
  5. 17
      src/web/html/style.css
  6. 87
      src/web/html/wizard.html
  7. 11
      src/web/web.h
  8. 7
      src/wifi/ahoywifi.cpp
  9. 9
      src/wifi/ahoywifi.h

1
src/CHANGES.md

@ -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

@ -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() {

3
src/appInterface.h

@ -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;

12
src/web/RestApi.h

@ -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")];

17
src/web/html/style.css

@ -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

@ -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>

11
src/web/web.h

@ -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"));

7
src/wifi/ahoywifi.cpp

@ -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;

9
src/wifi/ahoywifi.h

@ -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…
Cancel
Save