Improve wifi fallback

This commit is contained in:
Robert Strouse 2024-03-03 08:33:19 -08:00
parent ea5614c700
commit 60af2bf399
14 changed files with 133 additions and 69 deletions

View file

@ -125,6 +125,29 @@ bool ConfigFile::readString(char *buff, size_t len) {
_rtrim(buff);
return true;
}
bool ConfigFile::skipValue(size_t len) {
if(!this->file) return false;
uint8_t quotes = 0;
uint8_t j = 0;
while(j < len) {
uint8_t val;
j++;
if(this->file.read(&val, 1) == 1) {
switch(val) {
case CFG_VALUE_SEP:
if(quotes >= 2 || quotes == 0) return true;
break;
case CFG_REC_END:
return true;
case CFG_TOK_QUOTE:
quotes++;
break;
}
}
else return false;
}
return true;
}
bool ConfigFile::readVarString(char *buff, size_t len) {
if(!this->file) return false;
memset(buff, 0x00, len);
@ -564,8 +587,8 @@ bool ShadeConfigFile::restoreFile(SomfyShadeController *s, const char *filename,
else {
this->file.seek(this->file.position() + this->header.settingsRecordSize, SeekSet);
}
if(opts.network) {
this->readNetRecord();
if(opts.network || opts.mqtt) {
this->readNetRecord(opts);
}
else {
this->file.seek(this->file.position() + this->header.netRecordSize, SeekSet);
@ -583,44 +606,68 @@ bool ShadeConfigFile::restoreFile(SomfyShadeController *s, const char *filename,
settings.WIFI.save();
settings.Ethernet.save();
}
if(opts.mqtt) settings.MQTT.save();
return true;
}
bool ShadeConfigFile::readNetRecord() {
bool ShadeConfigFile::readNetRecord(restore_options_t &opts) {
if(this->header.netRecordSize > 0) {
uint32_t startPos = this->file.position();
Serial.println("Reading network settings from file...");
settings.connType = static_cast<conn_types>(this->readUInt8(static_cast<uint8_t>(conn_types::unset)));
settings.IP.dhcp = this->readBool(true);
char ip[24];
this->readVarString(ip, sizeof(ip));
settings.IP.ip.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.gateway.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.subnet.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.dns1.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.dns2.fromString(ip);
if(opts.network) {
Serial.println("Reading network settings from file...");
settings.connType = static_cast<conn_types>(this->readUInt8(static_cast<uint8_t>(conn_types::unset)));
settings.IP.dhcp = this->readBool(true);
char ip[24];
this->readVarString(ip, sizeof(ip));
settings.IP.ip.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.gateway.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.subnet.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.dns1.fromString(ip);
this->readVarString(ip, sizeof(ip));
settings.IP.dns2.fromString(ip);
}
else {
this->skipValue(4); // connType
this->skipValue(6); // dhcp flag
this->skipValue(24); // ip
this->skipValue(24); // gateway
this->skipValue(24); // subnet
this->skipValue(24); // dns1
this->skipValue(24); // dns2
}
if(this->header.version >= 22) {
this->readVarString(settings.MQTT.protocol, sizeof(settings.MQTT.protocol));
this->readVarString(settings.MQTT.hostname, sizeof(settings.MQTT.hostname));
settings.MQTT.port = this->readUInt16(1883);
settings.MQTT.pubDisco = this->readBool(false);
this->readVarString(settings.MQTT.rootTopic, sizeof(settings.MQTT.rootTopic));
this->readVarString(settings.MQTT.discoTopic, sizeof(settings.MQTT.discoTopic));
if(opts.mqtt) {
this->readVarString(settings.MQTT.protocol, sizeof(settings.MQTT.protocol));
this->readVarString(settings.MQTT.hostname, sizeof(settings.MQTT.hostname));
settings.MQTT.port = this->readUInt16(1883);
settings.MQTT.pubDisco = this->readBool(false);
this->readVarString(settings.MQTT.rootTopic, sizeof(settings.MQTT.rootTopic));
this->readVarString(settings.MQTT.discoTopic, sizeof(settings.MQTT.discoTopic));
}
else {
this->skipValue(sizeof(settings.MQTT.protocol));
this->skipValue(sizeof(settings.MQTT.hostname));
this->skipValue(6); // Port
this->skipValue(6); // pubDisco
this->skipValue(sizeof(settings.MQTT.rootTopic));
this->skipValue(sizeof(settings.MQTT.discoTopic));
}
}
// Now lets check to see if we are the same board. If we are then we will restore
// the ethernet phy settings.
if(strncmp(settings.serverId, this->header.serverId, sizeof(settings.serverId)) == 0) {
Serial.println("Restoring Ethernet adapter settings");
settings.Ethernet.boardType = this->readUInt8(1);
settings.Ethernet.phyType = static_cast<eth_phy_type_t>(this->readUInt8(0));
settings.Ethernet.CLKMode = static_cast<eth_clock_mode_t>(this->readUInt8(0));
settings.Ethernet.phyAddress = this->readInt8(1);
settings.Ethernet.PWRPin = this->readInt8(1);
settings.Ethernet.MDCPin = this->readInt8(16);
settings.Ethernet.MDIOPin = this->readInt8(23);
if(opts.network) {
if(strncmp(settings.serverId, this->header.serverId, sizeof(settings.serverId)) == 0) {
Serial.println("Restoring Ethernet adapter settings");
settings.Ethernet.boardType = this->readUInt8(1);
settings.Ethernet.phyType = static_cast<eth_phy_type_t>(this->readUInt8(0));
settings.Ethernet.CLKMode = static_cast<eth_clock_mode_t>(this->readUInt8(0));
settings.Ethernet.phyAddress = this->readInt8(1);
settings.Ethernet.PWRPin = this->readInt8(1);
settings.Ethernet.MDCPin = this->readInt8(16);
settings.Ethernet.MDIOPin = this->readInt8(23);
}
}
if(this->file.position() != startPos + this->header.netRecordSize) {
Serial.println("Reading to end of network record");

View file

@ -55,6 +55,7 @@ class ConfigFile {
bool writeFloat(const float val, const uint8_t prec, const char tok = CFG_VALUE_SEP);
bool readString(char *buff, size_t len);
bool readVarString(char *buff, size_t len);
bool skipValue(size_t len);
bool writeString(const char *val, size_t len, const char tok = CFG_VALUE_SEP);
bool writeVarString(const char *val, const char tok = CFG_VALUE_SEP);
char readChar(const char defVal = '\0');
@ -79,7 +80,7 @@ class ShadeConfigFile : public ConfigFile {
bool readShadeRecord(SomfyShade *shade);
bool readGroupRecord(SomfyGroup *group);
bool readSettingsRecord();
bool readNetRecord();
bool readNetRecord(restore_options_t &opts);
bool readTransRecord(transceiver_config_t &cfg);
public:
static bool exists();

View file

@ -15,6 +15,7 @@ void restore_options_t::fromJSON(JsonObject &obj) {
if(obj.containsKey("network")) this->network = obj["network"];
if(obj.containsKey("transceiver")) this->transceiver = obj["transceiver"];
if(obj.containsKey("repeaters")) this->repeaters = obj["repeaters"];
if(obj.containsKey("mqtt")) this->mqtt = obj["mqtt"];
}
int8_t appver_t::compare(appver_t &ver) {
if(this->major == ver.major && this->minor == ver.minor && this->build == ver.build) return 0;
@ -571,7 +572,7 @@ void WifiSettings::print() {
Serial.println("]");
}
void WifiSettings::printNetworks() {
int n = WiFi.scanNetworks(false, true);
int n = WiFi.scanNetworks(false, false);
Serial.print("Scanned ");
Serial.print(n);
Serial.println(" Networks...");

View file

@ -3,7 +3,7 @@
#ifndef configsettings_h
#define configsettings_h
#define FW_VERSION "v2.4.0"
#define FW_VERSION "v2.4.1"
enum DeviceStatus {
DS_OK = 0,
DS_ERROR = 1,
@ -15,6 +15,7 @@ struct restore_options_t {
bool network = false;
bool transceiver = false;
bool repeaters = false;
bool mqtt = false;
void fromJSON(JsonObject &obj);
};
struct appver_t {

View file

@ -25,9 +25,11 @@ void Network::end() {
}
bool Network::setup() {
WiFi.persistent(false);
WiFi.onEvent(this->networkEvent);
if(WiFi.status() == WL_CONNECTED) WiFi.disconnect(true);
if(settings.connType == conn_types::wifi || settings.connType == conn_types::unset) {
WiFi.persistent(false);
if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname);
Serial.print("WiFi Mode: ");
Serial.println(WiFi.getMode());
WiFi.mode(WIFI_STA);
@ -71,7 +73,8 @@ void Network::loop() {
mqtt.loop();
}
void Network::emitSockets() {
if(this->needsBroadcast || abs(abs(WiFi.RSSI()) - abs(this->lastRSSI)) > 1 || WiFi.channel() != this->lastChannel) {
if(this->needsBroadcast ||
(this->connType == conn_types::wifi && (abs(abs(WiFi.RSSI()) - abs(this->lastRSSI)) > 1 || WiFi.channel() != this->lastChannel))) {
this->emitSockets(255);
sockEmit.loop();
this->needsBroadcast = false;
@ -230,14 +233,23 @@ void Network::setConnected(conn_types connType) {
else if(SSDP.isStarted) SSDP.end();
this->emitSockets();
settings.printAvailHeap();
this->needsBroadcast = true;
}
bool Network::connectWired() {
//if(this->connType == conn_types::ethernet && ETH.linkUp()) {
if(ETH.linkUp()) {
this->disconnected = 0;
if(WiFi.status() == WL_CONNECTED) {
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
if(this->connType != conn_types::ethernet) this->setConnected(conn_types::ethernet);
this->wifiFallback = false;
return true;
}
else if(this->ethStarted) {
if(settings.connType == conn_types::ethernetpref && settings.WIFI.ssid[0] != '\0')
return this->connectWiFi();
}
if(this->connectAttempts > 0) {
Serial.printf("Ethernet Connection Lost... %d Reconnecting ", this->connectAttempts);
Serial.println(this->mac);
@ -248,12 +260,16 @@ bool Network::connectWired() {
if(!this->ethStarted) {
this->ethStarted = true;
WiFi.mode(WIFI_OFF);
WiFi.onEvent(this->networkEvent);
if(settings.hostname[0] != '\0') ETH.setHostname(settings.hostname);
if(settings.hostname[0] != '\0')
ETH.setHostname(settings.hostname);
else
ETH.setHostname("ESPSomfy-RTS");
Serial.print("Set hostname to:");
Serial.println(ETH.getHostname());
if(!ETH.begin(settings.Ethernet.phyAddress, settings.Ethernet.PWRPin, settings.Ethernet.MDCPin, settings.Ethernet.MDIOPin, settings.Ethernet.phyType, settings.Ethernet.CLKMode)) {
Serial.println("Ethernet Begin failed");
this->ethStarted = false;
if(settings.connType == conn_types::ethernetpref) {
this->wifiFallback = true;
return connectWiFi();
@ -272,7 +288,11 @@ bool Network::connectWired() {
uint32_t wait = millis();
while(millis() - wait < 14000) {
if(this->connected()) return true;
if(ETH.linkUp()) {
net.mac = ETH.macAddress();
net.setConnected(conn_types::ethernet);
return true;
}
delay(500);
}
if(settings.connType == conn_types::ethernetpref) {
@ -281,12 +301,6 @@ bool Network::connectWired() {
}
}
}
int retries = 0;
while(retries++ < 100) {
delay(100);
if(this->connected()) return true;
}
if(this->connectAttempts > 10) this->wifiFallback = true;
return false;
}
void Network::updateHostname() {
@ -326,7 +340,7 @@ bool Network::connectWiFi() {
this->connectStart = millis();
WiFi.setSleep(false);
WiFi.mode(WIFI_MODE_NULL);
WiFi.onEvent(this->networkEvent);
//WiFi.onEvent(this->networkEvent);
if(!settings.IP.dhcp) {
if(!WiFi.config(settings.IP.ip, settings.IP.gateway, settings.IP.subnet, settings.IP.dns1, settings.IP.dns2))
@ -397,12 +411,15 @@ bool Network::connect() {
if(settings.connType == conn_types::unset) return true;
else if(settings.connType == conn_types::ethernet || (settings.connType == conn_types::ethernetpref)) {
bool bConnected = this->connectWired();
if(!bConnected && settings.connType == conn_types::ethernetpref && settings.WIFI.ssid[0] != '\0')
if(!bConnected && settings.connType == conn_types::ethernetpref && settings.WIFI.ssid[0] != '\0') {
bConnected = this->connectWiFi();
this->wifiFallback = true;
}
return bConnected;
}
return this->connectWiFi();
}
/* DEPRECATED 03-02-24
int Network::getStrengthByMac(const char *macAddr) {
int n = WiFi.scanNetworks(true);
for(int i = 0; i < n; i++) {
@ -411,6 +428,7 @@ int Network::getStrengthByMac(const char *macAddr) {
}
return -100;
}
*/
uint32_t Network::getChipId() {
uint32_t chipId = 0;
uint64_t mac = ESP.getEfuseMac();
@ -421,7 +439,7 @@ uint32_t Network::getChipId() {
}
int Network::getStrengthBySSID(const char *ssid) {
int32_t strength = -100;
int n = WiFi.scanNetworks(false, true);
int n = WiFi.scanNetworks(false, false);
for(int i = 0; i < n; i++) {
if(WiFi.SSID(i).compareTo(ssid) == 0) strength = max(WiFi.RSSI(i), strength);
}
@ -516,18 +534,12 @@ void Network::networkEvent(WiFiEvent_t event) {
switch(event) {
case ARDUINO_EVENT_ETH_START:
Serial.println("Ethernet Started");
if(settings.hostname[0] != '\0')
ETH.setHostname(settings.hostname);
else
ETH.setHostname("ESPSomfy-RTS");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
// If the Wifi is connected then drop that connection
if(WiFi.status() == WL_CONNECTED) WiFi.disconnect(true);
Serial.print("Got Ethernet IP ");
Serial.println(ETH.localIP());
net.mac = ETH.macAddress();
net.setConnected(conn_types::ethernet);
break;
/*
case ARDUINO_EVENT_ETH_LOST_IP:
@ -539,12 +551,12 @@ void Network::networkEvent(WiFiEvent_t event) {
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.print("Ethernet Connected ");
// We don't want to call setConnected if we do not have an IP address yet
if(ETH.localIP() != INADDR_NONE)
net.setConnected(conn_types::ethernet);
//if(ETH.localIP() != INADDR_NONE)
// net.setConnected(conn_types::ethernet);
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("Ethernet Disconnected");
sockEmit.sendToClients("ethernet", "{\"connected\":false, \"speed\":0,\"fullduplex\":false}");
sockEmit.sendToClients("ethernet", "{\"connected\":false,\"speed\":0,\"fullduplex\":false}");
net.connType = conn_types::unset;
break;
case ARDUINO_EVENT_ETH_STOP:

View file

@ -29,7 +29,7 @@ class Network {
bool connectWiFi();
bool connectWired();
void setConnected(conn_types connType);
int getStrengthByMac(const char *mac);
//int getStrengthByMac(const char *mac);
int getStrengthBySSID(const char *ssid);
void updateHostname();
bool setup();

View file

@ -196,6 +196,7 @@ void SocketEmitter::wsEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t
git.emitUpdateCheck(num);
net.emitSockets(num);
sockServer.loop();
net.needsBroadcast = true;
}
break;
case WStype_TEXT:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -9,13 +9,13 @@
unsigned long Timestamp::epoch() {
struct tm tmNow;
time_t now;
if(!getLocalTime(&tmNow)) return 0;
if(!getLocalTime(&tmNow,50)) return 0;
time(&now);
return now;
}
time_t Timestamp::now() {
struct tm tmNow;
getLocalTime(&tmNow);
getLocalTime(&tmNow,50);
return mktime(&tmNow);
}
time_t Timestamp::getUTC() {

View file

@ -1 +1 @@
2.4.0
2.4.1

View file

@ -3,11 +3,11 @@
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="main.css?v=2.4.0c" type="text/css" />
<link rel="stylesheet" href="widgets.css?v=2.4.0c" type="text/css" />
<link rel="stylesheet" href="icons.css?v=2.4.0c" type="text/css" />
<link rel="stylesheet" href="main.css?v=2.4.1a" type="text/css" />
<link rel="stylesheet" href="widgets.css?v=2.4.1a" type="text/css" />
<link rel="stylesheet" href="icons.css?v=2.4.1a" type="text/css" />
<link rel="icon" type="image/png" href="favicon.png" />
<script type="text/javascript" src="index.js?v=2.4.0c"></script>
<script type="text/javascript" src="index.js?v=2.4.1a"></script>
</head>
<body>
<div id="divContainer" class="container main" data-auth="false">

View file

@ -1264,7 +1264,7 @@ var security = new Security();
class General {
initialized = false;
appVersion = 'v2.4.0';
appVersion = 'v2.4.1';
reloadApp = false;
init() {
if (this.initialized) return;
@ -4254,12 +4254,13 @@ class Firmware {
let div = this.createFileUploader('/restore');
let inst = div.querySelector('div[id=divInstText]');
let html = '<div style="font-size:14px;">Select a backup file that you would like to restore and the options you would like to restore then press the Upload File button.</div><hr />';
html += `<div style="font-size:14px;">Restoring network settings from a different board than the original will ignore Ethernet chip settings. Security, MQTT and WiFi will also not be restored since backup files do not contain passwords.</div><hr/>`;
html += `<div style="font-size:14px;">Restoring network settings from a different board than the original will ignore Ethernet chip settings. Security, MQTT and WiFi connection information will also not be restored since backup files do not contain passwords.</div><hr/>`;
html += '<div style="font-size:14px;margin-bottom:27px;text-align:left;margin-left:70px;">';
html += `<div class="field-group" style="vertical-align:middle;width:auto;"><input id="cbRestoreShades" type="checkbox" data-bind="shades" style="display:inline-block;" checked="true" /><label for="cbRestoreShades" style="display:inline-block;cursor:pointer;color:white;">Restore Shades and Groups</label></div>`;
html += `<div class="field-group" style="vertical-align:middle;width:auto;"><input id="cbRestoreRepeaters" type="checkbox" data-bind="repeaters" style="display:inline-block;" /><label for="cbRestoreRepeaters" style="display:inline-block;cursor:pointer;color:white;">Restore Repeaters</label></div>`;
html += `<div class="field-group" style="vertical-align:middle;width:auto;"><input id="cbRestoreSystem" type="checkbox" data-bind="settings" style="display:inline-block;" /><label for="cbRestoreSystem" style="display:inline-block;cursor:pointer;color:white;">Restore System Settings</label></div>`;
html += `<div class="field-group" style="vertical-align:middle;width:auto;"><input id="cbRestoreNetwork" type="checkbox" data-bind="network" style="display:inline-block;" /><label for="cbRestoreNetwork" style="display:inline-block;cursor:pointer;color:white;">Restore Network Settings</label></div>`
html += `<div class="field-group" style="vertical-align:middle;width:auto;"><input id="cbRestoreMQTT" type="checkbox" data-bind="mqtt" style="display:inline-block;" /><label for="cbRestoreMQTT" style="display:inline-block;cursor:pointer;color:white;">Restore MQTT Settings</label></div>`
html += `<div class="field-group" style="vertical-align:middle;width:auto;"><input id="cbRestoreTransceiver" type="checkbox" data-bind="transceiver" style="display:inline-block;" /><label for="cbRestoreTransceiver" style="display:inline-block;cursor:pointer;color:white;">Restore Radio Settings</label></div>`;
html += '</div>';
inst.innerHTML = html;
@ -4633,7 +4634,7 @@ class Firmware {
ui.errorMessage(el, 'This file is not a valid backup file');
return;
}
if (!data.shades && !data.settings && !data.network && !data.transceiver && !data.repeaters) {
if (!data.shades && !data.settings && !data.network && !data.transceiver && !data.repeaters && !data.mqtt) {
ui.errorMessage(el, 'No restore options have been selected');
return;
}