Merge pull request #473 from iranl/http-server

Switch HTTP server to PsychicHTTP and MQTT client to ESP-MQTT, remove WiFiManager
This commit is contained in:
Alessandro Del Prete
2024-10-17 05:48:15 +02:00
committed by GitHub
406 changed files with 22877 additions and 32732 deletions

View File

@@ -4,7 +4,7 @@
#define NUKI_HUB_VERSION "9.02"
#define NUKI_HUB_BUILD "unknownbuildnr"
#define NUKI_HUB_DATE "2024-10-13"
#define NUKI_HUB_DATE "unknowndate"
#define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest"
#define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json"

View File

@@ -5,5 +5,5 @@
class MqttReceiver
{
public:
virtual void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) = 0;
virtual void onMqttDataReceived(char* topic, int topic_len, char* data, int data_len) = 0;
};

File diff suppressed because it is too large Load Diff

View File

@@ -10,14 +10,13 @@
#ifndef NUKI_HUB_UPDATER
#include "MqttReceiver.h"
#include "mqtt_client.h"
#include "MqttTopics.h"
#include "Gpio.h"
#include <ArduinoJson.h>
#include "NukiConstants.h"
#endif
#define JSON_BUFFER_SIZE 1024
class NukiNetwork
{
public:
@@ -25,6 +24,8 @@ public:
void readSettings();
bool update();
void reconfigureDevice();
void scan(bool passive = false, bool async = true);
bool isApOpen();
void clearWifiFallback();
const String networkDeviceName() const;
@@ -86,7 +87,6 @@ public:
void timeZoneIdToString(const Nuki::TimeZoneId timeZoneId, char* str);
int mqttConnectionState(); // 0 = not connected; 1 = connected; 2 = connected and mqtt processed
bool encryptionSupported();
bool mqttRecentlyConnected();
bool pathEquals(const char* prefix, const char* path, const char* referencePath);
uint16_t subscribe(const char* topic, uint8_t qos);
@@ -117,9 +117,10 @@ private:
bool _offEnabled = false;
#ifndef NUKI_HUB_UPDATER
static void onMqttDataReceivedCallback(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
void onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total);
void parseGpioTopics(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total);
static void mqtt_event_handler_cb(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
void onMqttDataReceived(char* topic, int topic_len, char* data, int data_len);
void parseGpioTopics(char* topic, int topic_len, char* data, int data_len);
void gpioActionCallback(const GpioAction& action, const int& pin);
String createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
@@ -136,10 +137,6 @@ private:
const String& commandTopic = "",
std::vector<std::pair<char*, char*>> additionalEntries = {}
);
void onMqttConnect(const bool& sessionPresent);
void onMqttDisconnect(const espMqttClientTypes::DisconnectReason& reason);
void buildMqttPath(char* outPath, std::initializer_list<const char*> paths);
const char* _lastWillPayload = "offline";
@@ -148,13 +145,20 @@ private:
String _discoveryTopic;
Gpio* _gpio;
esp_mqtt_client_config_t _mqtt_cfg = { 0 };
bool _mqttClientInitiated = false;
int _mqttConnectionState = 0;
bool _mqttConnected = false;
int _mqttConnectCounter = 0;
int _mqttPort = 1883;
long _mqttConnectedTs = -1;
bool _connectReplyReceived = false;
bool _firstDisconnected = true;
esp_mqtt_client_handle_t _mqttClient;
char _ca[TLS_CA_MAX_SIZE] = {0};
char _cert[TLS_CERT_MAX_SIZE] = {0};
char _key[TLS_KEY_MAX_SIZE] = {0};
int64_t _nextReconnect = 0;
char _mqttBrokerAddr[101] = {0};
@@ -166,7 +170,6 @@ private:
std::vector<MqttReceiver*> _mqttReceivers;
bool _restartOnDisconnect = false;
bool _checkUpdates = false;
bool _reconnectNetworkOnMqttDisconnect = false;
bool _firstConnect = true;
bool _publishDebugInfo = false;
bool _logIp = true;

View File

@@ -178,24 +178,22 @@ void NukiNetworkLock::update()
}
}
void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
void NukiNetworkLock::onMqttDataReceived(char* topic, int topic_len, char* data, int data_len)
{
char* value = (char*)payload;
if(_network->mqttRecentlyConnected() && _network->pathEquals(_mqttPath, mqtt_topic_lock_action, topic))
{
Log->println("MQTT recently connected, ignoring lock action.");
return;
}
if(comparePrefixedPath(topic, mqtt_topic_reset) && strcmp(value, "1") == 0)
if(comparePrefixedPath(topic, mqtt_topic_reset) && strcmp(data, "1") == 0)
{
Log->println(F("Restart requested via MQTT."));
_network->clearWifiFallback();
delay(200);
restartEsp(RestartReason::RequestedViaMqtt);
}
else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(value, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false))
else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(data, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false))
{
Log->println(F("Update requested via MQTT."));
@@ -297,17 +295,17 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
}
else if(comparePrefixedPath(topic, mqtt_topic_webserver_action))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 ||
strcmp(data, "--") == 0) return;
if(strcmp(value, "1") == 0)
if(strcmp(data, "1") == 0)
{
if(_preferences->getBool(preference_webserver_enabled, true) || forceEnableWebServer) return;
Log->println(F("Webserver enabled, restarting."));
_preferences->putBool(preference_webserver_enabled, true);
}
else if (strcmp(value, "0") == 0)
else if (strcmp(data, "0") == 0)
{
if(!_preferences->getBool(preference_webserver_enabled, true) && !forceEnableWebServer) return;
Log->println(F("Webserver disabled, restarting."));
@@ -321,10 +319,10 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
}
else if(comparePrefixedPath(topic, mqtt_topic_lock_log_rolling_last))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 ||
strcmp(data, "--") == 0) return;
if(atoi(value) > 0 && atoi(value) > _lastRollingLog) _lastRollingLog = atoi(value);
if(atoi(data) > 0 && atoi(data) > _lastRollingLog) _lastRollingLog = atoi(data);
}
if(_nukiOfficial->getOffEnabled())
@@ -335,7 +333,7 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
{
if(_officialUpdateReceivedCallback != nullptr)
{
_officialUpdateReceivedCallback(offTopic, value);
_officialUpdateReceivedCallback(offTopic, data);
}
}
}
@@ -343,19 +341,19 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
if(comparePrefixedPath(topic, mqtt_topic_lock_action))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0 ||
strcmp(value, "ack") == 0 ||
strcmp(value, "unknown_action") == 0 ||
strcmp(value, "denied") == 0 ||
strcmp(value, "error") == 0) return;
if(strcmp(data, "") == 0 ||
strcmp(data, "--") == 0 ||
strcmp(data, "ack") == 0 ||
strcmp(data, "unknown_action") == 0 ||
strcmp(data, "denied") == 0 ||
strcmp(data, "error") == 0) return;
Log->print(F("Lock action received: "));
Log->println(value);
Log->println(data);
LockActionResult lockActionResult = LockActionResult::Failed;
if(_lockActionReceivedCallback != NULL)
{
lockActionResult = _lockActionReceivedCallback(value);
lockActionResult = _lockActionReceivedCallback(data);
}
switch(lockActionResult)
@@ -381,16 +379,16 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
{
if(_keypadCommandReceivedReceivedCallback != nullptr)
{
if(strcmp(value, "--") == 0) return;
if(strcmp(data, "--") == 0) return;
_keypadCommandReceivedReceivedCallback(value, _keypadCommandId, _keypadCommandName, _keypadCommandCode, _keypadCommandEnabled);
_keypadCommandReceivedReceivedCallback(data, _keypadCommandId, _keypadCommandName, _keypadCommandCode, _keypadCommandEnabled);
_keypadCommandId = 0;
_keypadCommandName = "--";
_keypadCommandCode = "000000";
_keypadCommandEnabled = 1;
if(strcmp(value, "--") != 0)
if(strcmp(data, "--") != 0)
{
publishString(mqtt_topic_keypad_command_action, "--", true);
}
@@ -402,38 +400,38 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_id))
{
_keypadCommandId = atoi(value);
_keypadCommandId = atoi(data);
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_name))
{
_keypadCommandName = value;
_keypadCommandName = data;
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_code))
{
_keypadCommandCode = value;
_keypadCommandCode = data;
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_enabled))
{
_keypadCommandEnabled = atoi(value);
_keypadCommandEnabled = atoi(data);
}
}
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(value, "1") == 0)
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_CONFIG;
publishString(mqtt_topic_query_config, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(value, "1") == 0)
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_LOCKSTATE;
publishString(mqtt_topic_query_lockstate, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(value, "1") == 0)
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_KEYPAD;
publishString(mqtt_topic_query_keypad, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(value, "1") == 0)
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_BATTERY;
publishString(mqtt_topic_query_battery, "0", true);
@@ -441,11 +439,11 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
if(comparePrefixedPath(topic, mqtt_topic_config_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_configUpdateReceivedCallback != NULL)
{
_configUpdateReceivedCallback(value);
_configUpdateReceivedCallback(data);
}
publishString(mqtt_topic_config_action, "--", true);
@@ -453,11 +451,11 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
if(comparePrefixedPath(topic, mqtt_topic_keypad_json_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_keypadJsonCommandReceivedReceivedCallback != NULL)
{
_keypadJsonCommandReceivedReceivedCallback(value);
_keypadJsonCommandReceivedReceivedCallback(data);
}
publishString(mqtt_topic_keypad_json_action, "--", true);
@@ -465,11 +463,11 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_timeControlCommandReceivedReceivedCallback != NULL)
{
_timeControlCommandReceivedReceivedCallback(value);
_timeControlCommandReceivedReceivedCallback(data);
}
publishString(mqtt_topic_timecontrol_action, "--", true);
@@ -477,11 +475,11 @@ void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const
if(comparePrefixedPath(topic, mqtt_topic_auth_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_authCommandReceivedReceivedCallback != NULL)
{
_authCommandReceivedReceivedCallback(value);
_authCommandReceivedReceivedCallback(data);
}
publishString(mqtt_topic_auth_action, "--", true);

View File

@@ -15,8 +15,6 @@
#include "NukiOfficial.h"
#include "NukiPublisher.h"
#define LOCK_LOG_JSON_BUFFER_SIZE 2048
class NukiNetworkLock : public MqttReceiver
{
public:
@@ -58,7 +56,7 @@ public:
void setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char* value));
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
void setAuthCommandReceivedCallback(void (*authCommandReceivedReceivedCallback)(const char* value));
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
void onMqttDataReceived(char* topic, int topic_len, char* data, int data_len) override;
void publishFloat(const char* topic, const float value, bool retain, const uint8_t precision = 2);
void publishInt(const char* topic, const int value, bool retain);

View File

@@ -138,10 +138,8 @@ void NukiNetworkOpener::update()
}
}
void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
void NukiNetworkOpener::onMqttDataReceived(char* topic, int topic_len, char* data, int data_len)
{
char* value = (char*)payload;
if(_network->mqttRecentlyConnected() && _network->pathEquals(_mqttPath, mqtt_topic_lock_action, topic))
{
Log->println("MQTT recently connected, ignoring opener action.");
@@ -150,27 +148,27 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
if(comparePrefixedPath(topic, mqtt_topic_lock_log_rolling_last))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 ||
strcmp(data, "--") == 0) return;
if(atoi(value) > 0 && atoi(value) > _lastRollingLog) _lastRollingLog = atoi(value);
if(atoi(data) > 0 && atoi(data) > _lastRollingLog) _lastRollingLog = atoi(data);
}
if(comparePrefixedPath(topic, mqtt_topic_lock_action))
{
if(strcmp(value, "") == 0 ||
strcmp(value, "--") == 0 ||
strcmp(value, "ack") == 0 ||
strcmp(value, "unknown_action") == 0 ||
strcmp(value, "denied") == 0 ||
strcmp(value, "error") == 0) return;
if(strcmp(data, "") == 0 ||
strcmp(data, "--") == 0 ||
strcmp(data, "ack") == 0 ||
strcmp(data, "unknown_action") == 0 ||
strcmp(data, "denied") == 0 ||
strcmp(data, "error") == 0) return;
Log->print(F("Opener action received: "));
Log->println(value);
Log->println(data);
LockActionResult lockActionResult = LockActionResult::Failed;
if(_lockActionReceivedCallback != NULL)
{
lockActionResult = _lockActionReceivedCallback(value);
lockActionResult = _lockActionReceivedCallback(data);
}
switch(lockActionResult)
@@ -196,16 +194,16 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
{
if(_keypadCommandReceivedReceivedCallback != nullptr)
{
if(strcmp(value, "--") == 0) return;
if(strcmp(data, "--") == 0) return;
_keypadCommandReceivedReceivedCallback(value, _keypadCommandId, _keypadCommandName, _keypadCommandCode, _keypadCommandEnabled);
_keypadCommandReceivedReceivedCallback(data, _keypadCommandId, _keypadCommandName, _keypadCommandCode, _keypadCommandEnabled);
_keypadCommandId = 0;
_keypadCommandName = "--";
_keypadCommandCode = "000000";
_keypadCommandEnabled = 1;
if(strcmp(value, "--") != 0)
if(strcmp(data, "--") != 0)
{
publishString(mqtt_topic_keypad_command_action, "--", true);
}
@@ -217,38 +215,38 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_id))
{
_keypadCommandId = atoi(value);
_keypadCommandId = atoi(data);
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_name))
{
_keypadCommandName = value;
_keypadCommandName = data;
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_code))
{
_keypadCommandCode = value;
_keypadCommandCode = data;
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_enabled))
{
_keypadCommandEnabled = atoi(value);
_keypadCommandEnabled = atoi(data);
}
}
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(value, "1") == 0)
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_CONFIG;
publishString(mqtt_topic_query_config, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(value, "1") == 0)
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_LOCKSTATE;
publishString(mqtt_topic_query_lockstate, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(value, "1") == 0)
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_KEYPAD;
publishString(mqtt_topic_query_keypad, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(value, "1") == 0)
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_BATTERY;
publishString(mqtt_topic_query_battery, "0", true);
@@ -256,11 +254,11 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
if(comparePrefixedPath(topic, mqtt_topic_config_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_configUpdateReceivedCallback != NULL)
{
_configUpdateReceivedCallback(value);
_configUpdateReceivedCallback(data);
}
publishString(mqtt_topic_config_action, "--", true);
@@ -268,11 +266,11 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
if(comparePrefixedPath(topic, mqtt_topic_keypad_json_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_keypadJsonCommandReceivedReceivedCallback != NULL)
{
_keypadJsonCommandReceivedReceivedCallback(value);
_keypadJsonCommandReceivedReceivedCallback(data);
}
publishString(mqtt_topic_keypad_json_action, "--", true);
@@ -280,11 +278,11 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_timeControlCommandReceivedReceivedCallback != NULL)
{
_timeControlCommandReceivedReceivedCallback(value);
_timeControlCommandReceivedReceivedCallback(data);
}
publishString(mqtt_topic_timecontrol_action, "--", true);
@@ -292,11 +290,11 @@ void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, con
if(comparePrefixedPath(topic, mqtt_topic_auth_action))
{
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
if(strcmp(data, "") == 0 || strcmp(data, "--") == 0) return;
if(_authCommandReceivedReceivedCallback != NULL)
{
_authCommandReceivedReceivedCallback(value);
_authCommandReceivedReceivedCallback(data);
}
publishString(mqtt_topic_auth_action, "--", true);

View File

@@ -47,7 +47,7 @@ public:
void setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char* value));
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
void setAuthCommandReceivedCallback(void (*authCommandReceivedReceivedCallback)(const char* value));
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
void onMqttDataReceived(char* topic, int topic_len, char* data, int data_len) override;
bool reconnected();
uint8_t queryCommands();

View File

@@ -1772,21 +1772,21 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
String allowedFromTime;
String allowedUntilTime;
if(json.containsKey("code")) code = json["code"].as<unsigned int>();
if(json["code"].is<unsigned int>()) code = json["code"].as<unsigned int>();
else code = 12;
if(json.containsKey("enabled")) enabled = json["enabled"].as<unsigned int>();
if(json["enabled"].is<unsigned int>()) enabled = json["enabled"].as<unsigned int>();
else enabled = 2;
if(json.containsKey("timeLimited")) timeLimited = json["timeLimited"].as<unsigned int>();
if(json["timeLimited"].is<unsigned int>()) timeLimited = json["timeLimited"].as<unsigned int>();
else timeLimited = 2;
if(json.containsKey("name")) name = json["name"].as<String>();
if(json.containsKey("allowedFrom")) allowedFrom = json["allowedFrom"].as<String>();
if(json.containsKey("allowedUntil")) allowedUntil = json["allowedUntil"].as<String>();
if(json.containsKey("allowedWeekdays")) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json.containsKey("allowedFromTime")) allowedFromTime = json["allowedFromTime"].as<String>();
if(json.containsKey("allowedUntilTime")) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(json["name"].is<String>()) name = json["name"].as<String>();
if(json["allowedFrom"].is<String>()) allowedFrom = json["allowedFrom"].as<String>();
if(json["allowedUntil"].is<String>()) allowedUntil = json["allowedUntil"].as<String>();
if(json["allowedWeekdays"].is<String>()) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json["allowedFromTime"].is<String>()) allowedFromTime = json["allowedFromTime"].as<String>();
if(json["allowedUntilTime"].is<String>()) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(action)
{
@@ -2209,12 +2209,12 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
String lockAction;
NukiOpener::LockAction timeControlLockAction;
if(json.containsKey("enabled")) enabled = json["enabled"].as<unsigned int>();
if(json["enabled"].is<unsigned int>()) enabled = json["enabled"].as<unsigned int>();
else enabled = 2;
if(json.containsKey("weekdays")) weekdays = json["weekdays"].as<String>();
if(json.containsKey("time")) time = json["time"].as<String>();
if(json.containsKey("lockAction")) lockAction = json["lockAction"].as<String>();
if(json["weekdays"].is<String>()) weekdays = json["weekdays"].as<String>();
if(json["time"].is<String>()) time = json["time"].as<String>();
if(json["lockAction"].is<String>()) lockAction = json["lockAction"].as<String>();
if(lockAction.length() > 0)
{
@@ -2443,22 +2443,22 @@ void NukiOpenerWrapper::onAuthCommandReceived(const char *value)
String allowedFromTime;
String allowedUntilTime;
if(json.containsKey("remoteAllowed")) remoteAllowed = json["remoteAllowed"].as<unsigned int>();
if(json["remoteAllowed"].is<unsigned int>()) remoteAllowed = json["remoteAllowed"].as<unsigned int>();
else remoteAllowed = 2;
if(json.containsKey("enabled")) enabled = json["enabled"].as<unsigned int>();
if(json["enabled"].is<unsigned int>()) enabled = json["enabled"].as<unsigned int>();
else enabled = 2;
if(json.containsKey("timeLimited")) timeLimited = json["timeLimited"].as<unsigned int>();
if(json["timeLimited"].is<unsigned int>()) timeLimited = json["timeLimited"].as<unsigned int>();
else timeLimited = 2;
if(json.containsKey("name")) name = json["name"].as<String>();
//if(json.containsKey("sharedKey")) sharedKey = json["sharedKey"].as<String>();
if(json.containsKey("allowedFrom")) allowedFrom = json["allowedFrom"].as<String>();
if(json.containsKey("allowedUntil")) allowedUntil = json["allowedUntil"].as<String>();
if(json.containsKey("allowedWeekdays")) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json.containsKey("allowedFromTime")) allowedFromTime = json["allowedFromTime"].as<String>();
if(json.containsKey("allowedUntilTime")) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(json["name"].is<String>()) name = json["name"].as<String>();
//if(json["sharedKey"].is<String>()) sharedKey = json["sharedKey"].as<String>();
if(json["allowedFrom"].is<String>()) allowedFrom = json["allowedFrom"].as<String>();
if(json["allowedUntil"].is<String>()) allowedUntil = json["allowedUntil"].as<String>();
if(json["allowedWeekdays"].is<String>()) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json["allowedFromTime"].is<String>()) allowedFromTime = json["allowedFromTime"].as<String>();
if(json["allowedUntilTime"].is<String>()) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(action)
{

View File

@@ -1,3 +1,6 @@
#ifndef CONFIG_IDF_TARGET_ESP32H2
#include "esp_wifi.h"
#endif
#include "NukiWrapper.h"
#include "PreferencesKeys.h"
#include "MqttTopics.h"
@@ -58,8 +61,24 @@ void NukiWrapper::initialize(const bool& firstStart)
if(firstStart)
{
Log->println("First start, setting preference defaults");
_preferences->putBool(preference_network_wifi_fallback_disabled, false);
_preferences->putBool(preference_find_best_rssi, false);
#ifndef CONFIG_IDF_TARGET_ESP32H2
wifi_config_t wifi_cfg;
if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
Log->println("Failed to get Wi-Fi configuration in RAM");
}
if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {
Log->println("Failed to set storage Wi-Fi");
}
memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
Log->println("Failed to clear NVS Wi-Fi configuration");
}
#endif
_preferences->putBool(preference_check_updates, true);
_preferences->putBool(preference_opener_continuous_mode, false);
_preferences->putBool(preference_official_hybrid_enabled, false);
@@ -1894,21 +1913,21 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
String allowedFromTime;
String allowedUntilTime;
if(json.containsKey("code")) code = json["code"].as<unsigned int>();
if(json["code"].is<unsigned int>()) code = json["code"].as<unsigned int>();
else code = 12;
if(json.containsKey("enabled")) enabled = json["enabled"].as<unsigned int>();
if(json["enabled"].is<unsigned int>()) enabled = json["enabled"].as<unsigned int>();
else enabled = 2;
if(json.containsKey("timeLimited")) timeLimited = json["timeLimited"].as<unsigned int>();
if(json["timeLimited"].is<unsigned int>()) timeLimited = json["timeLimited"].as<unsigned int>();
else timeLimited = 2;
if(json.containsKey("name")) name = json["name"].as<String>();
if(json.containsKey("allowedFrom")) allowedFrom = json["allowedFrom"].as<String>();
if(json.containsKey("allowedUntil")) allowedUntil = json["allowedUntil"].as<String>();
if(json.containsKey("allowedWeekdays")) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json.containsKey("allowedFromTime")) allowedFromTime = json["allowedFromTime"].as<String>();
if(json.containsKey("allowedUntilTime")) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(json["name"].is<String>()) name = json["name"].as<String>();
if(json["allowedFrom"].is<String>()) allowedFrom = json["allowedFrom"].as<String>();
if(json["allowedUntil"].is<String>()) allowedUntil = json["allowedUntil"].as<String>();
if(json["allowedWeekdays"].is<String>()) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json["allowedFromTime"].is<String>()) allowedFromTime = json["allowedFromTime"].as<String>();
if(json["allowedUntilTime"].is<String>()) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(action)
{
@@ -2331,12 +2350,12 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
String lockAction;
NukiLock::LockAction timeControlLockAction;
if(json.containsKey("enabled")) enabled = json["enabled"].as<unsigned int>();
if(json["enabled"].is<unsigned int>()) enabled = json["enabled"].as<unsigned int>();
else enabled = 2;
if(json.containsKey("weekdays")) weekdays = json["weekdays"].as<String>();
if(json.containsKey("time")) time = json["time"].as<String>();
if(json.containsKey("lockAction")) lockAction = json["lockAction"].as<String>();
if(json["weekdays"].is<String>()) weekdays = json["weekdays"].as<String>();
if(json["time"].is<String>()) time = json["time"].as<String>();
if(json["lockAction"].is<String>()) lockAction = json["lockAction"].as<String>();
if(lockAction.length() > 0)
{
@@ -2567,22 +2586,22 @@ void NukiWrapper::onAuthCommandReceived(const char *value)
String allowedFromTime;
String allowedUntilTime;
if(json.containsKey("remoteAllowed")) remoteAllowed = json["remoteAllowed"].as<unsigned int>();
if(json["remoteAllowed"].is<unsigned int>()) remoteAllowed = json["remoteAllowed"].as<unsigned int>();
else remoteAllowed = 2;
if(json.containsKey("enabled")) enabled = json["enabled"].as<unsigned int>();
if(json["enabled"].is<unsigned int>()) enabled = json["enabled"].as<unsigned int>();
else enabled = 2;
if(json.containsKey("timeLimited")) timeLimited = json["timeLimited"].as<unsigned int>();
if(json["timeLimited"].is<unsigned int>()) timeLimited = json["timeLimited"].as<unsigned int>();
else timeLimited = 2;
if(json.containsKey("name")) name = json["name"].as<String>();
//if(json.containsKey("sharedKey")) sharedKey = json["sharedKey"].as<String>();
if(json.containsKey("allowedFrom")) allowedFrom = json["allowedFrom"].as<String>();
if(json.containsKey("allowedUntil")) allowedUntil = json["allowedUntil"].as<String>();
if(json.containsKey("allowedWeekdays")) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json.containsKey("allowedFromTime")) allowedFromTime = json["allowedFromTime"].as<String>();
if(json.containsKey("allowedUntilTime")) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(json["name"].is<String>()) name = json["name"].as<String>();
//if(json["sharedKey"].is<String>()) sharedKey = json["sharedKey"].as<String>();
if(json["allowedFrom"].is<String>()) allowedFrom = json["allowedFrom"].as<String>();
if(json["allowedUntil"].is<String>()) allowedUntil = json["allowedUntil"].as<String>();
if(json["allowedWeekdays"].is<String>()) allowedWeekdays = json["allowedWeekdays"].as<String>();
if(json["allowedFromTime"].is<String>()) allowedFromTime = json["allowedFromTime"].as<String>();
if(json["allowedUntilTime"].is<String>()) allowedUntilTime = json["allowedUntilTime"].as<String>();
if(action)
{

View File

@@ -52,9 +52,10 @@
#define preference_update_from_mqtt (char*)"updMqtt"
#define preference_disable_non_json (char*)"disnonjson"
#define preference_official_hybrid_enabled (char*)"offHybrid"
#define preference_wifi_ssid (char*)"wifiSSID"
#define preference_wifi_pass (char*)"wifiPass"
// CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT
#define preference_find_best_rssi (char*)"nwbestrssi"
#define preference_ntw_reconfigure (char*)"ntwRECONF"
#define preference_auth_max_entries (char*)"authmaxentry"
#define preference_auth_info_enabled (char*)"authInfoEna"
@@ -88,14 +89,12 @@
#define preference_command_retry_delay (char*)"rtryDelay"
#define preference_query_interval_hybrid_lockstate (char*)"hybridTimer"
#define preference_mqtt_hass_cu_url (char*)"hassConfigUrl"
#define preference_network_wifi_fallback_disabled (char*)"nwwififb"
#define preference_check_updates (char*)"checkupdates"
#define preference_opener_continuous_mode (char*)"openercont"
#define preference_rssi_publish_interval (char*)"rssipb"
#define preference_network_timeout (char*)"nettmout"
#define preference_restart_on_disconnect (char*)"restdisc"
#define preference_publish_debug_info (char*)"pubdbg"
#define preference_recon_netw_on_mqtt_discon (char*)"recNtwMqttDis"
#define preference_official_hybrid_actions (char*)"hybridAct"
#define preference_official_hybrid_retry (char*)"hybridRtry"
@@ -118,12 +117,14 @@
#define preference_lock_max_timecontrol_entry_count (char*)"maxtc"
#define preference_opener_max_timecontrol_entry_count (char*)"opmaxtc"
#define preference_latest_version (char*)"latest"
#define preference_wifi_converted (char*)"wifiConv"
//OBSOLETE
#define preference_access_level (char*)"accLvl"
#define preference_gpio_locking_enabled (char*)"gpiolck"
#define preference_network_hardware_gpio (char*)"nwhwdt"
#define preference_presence_detection_timeout (char*)"prdtimeout"
#define preference_network_wifi_fallback_disabled (char*)"nwwififb"
inline bool initPreferences(Preferences* preferences)
{
@@ -248,9 +249,15 @@ inline bool initPreferences(Preferences* preferences)
if (configVer < 901)
{
#if defined(CONFIG_IDF_TARGET_ESP32S3)
if (preferences->getInt(preference_network_hardware) == 3) preferences->putInt(preference_network_hardware, 10);
if (preferences->getInt(preference_network_hardware) == 3)
{
preferences->putInt(preference_network_hardware, 10);
}
#endif
if (preferences->getInt(preference_network_hardware) == 2) preferences->putInt(preference_network_hardware, 3);
if (preferences->getInt(preference_network_hardware) == 2)
{
preferences->putInt(preference_network_hardware, 3);
}
}
preferences->putInt(preference_config_version, atof(NUKI_HUB_VERSION) * 100);
@@ -271,8 +278,8 @@ private:
preference_opener_continuous_mode, preference_mqtt_opener_path, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count,
preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt,
preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address,
preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_network_wifi_fallback_disabled,
preference_rssi_publish_interval, preference_hostname, preference_find_best_rssi, preference_network_timeout, preference_restart_on_disconnect,
preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware,
preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled,
preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_info_enabled,
@@ -280,26 +287,26 @@ private:
preference_cred_password, preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info,
preference_official_hybrid_enabled, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry,
preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries,
preference_update_from_mqtt, preference_show_secrets, preference_ble_tx_power, preference_recon_netw_on_mqtt_discon, preference_webserial_enabled,
preference_update_from_mqtt, preference_show_secrets, preference_ble_tx_power, preference_webserial_enabled,
preference_network_custom_mdc, preference_network_custom_clk, preference_network_custom_phy, preference_network_custom_addr, preference_network_custom_irq,
preference_network_custom_rst, preference_network_custom_cs, preference_network_custom_sck, preference_network_custom_miso, preference_network_custom_mosi,
preference_network_custom_pwr, preference_network_custom_mdio, preference_ntw_reconfigure, preference_lock_max_auth_entry_count, preference_opener_max_auth_entry_count,
preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries,
preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries, preference_wifi_ssid, preference_wifi_pass
};
std::vector<char*> _redact =
{
preference_mqtt_user, preference_mqtt_password, preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_cred_user, preference_cred_password,
preference_nuki_id_lock, preference_nuki_id_opener,
preference_nuki_id_lock, preference_nuki_id_opener, preference_wifi_pass
};
std::vector<char*> _boolPrefs =
{
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_find_best_rssi,
preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled,
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, preference_show_secrets,
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled,
preference_publish_authdata, preference_publish_debug_info, preference_network_wifi_fallback_disabled, preference_official_hybrid_enabled,
preference_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled,
preference_official_hybrid_actions, preference_official_hybrid_retry, preference_conf_info_enabled, preference_disable_non_json, preference_update_from_mqtt,
preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_recon_netw_on_mqtt_discon, preference_webserial_enabled,
preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_webserial_enabled,
preference_ntw_reconfigure
};
std::vector<char*> _bytePrefs =

View File

@@ -33,12 +33,9 @@ enum class RestartReason
extern int restartReason;
extern uint64_t restartReasonValidDetect;
extern bool rebuildGpioRequested;
extern RestartReason currentRestartReason;
extern bool restartReason_isValid;
inline static void restartEsp(RestartReason reason)
{
if(reason == RestartReason::GpioConfigurationUpdated)

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
#pragma once
#include <Preferences.h>
#include <AsyncTCP.h>
#include <DNSServer.h>
#include <ESPAsyncWebServer.h>
#include <PsychicHttp.h>
#include <PsychicHttpsServer.h>
#include "esp_ota_ops.h"
#include "Config.h"
@@ -37,9 +36,9 @@ class WebCfgServer
{
public:
#ifndef NUKI_HUB_UPDATER
WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, AsyncWebServer* asyncServer);
WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer);
#else
WebCfgServer(NukiNetwork* network, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, AsyncWebServer* asyncServer);
WebCfgServer(NukiNetwork* network, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType, PsychicHttpServer* psychicServer);
#endif
~WebCfgServer() = default;
@@ -47,34 +46,32 @@ public:
private:
#ifndef NUKI_HUB_UPDATER
void sendSettings(AsyncWebServerRequest *request);
bool processArgs(AsyncWebServerRequest *request, String& message);
bool processImport(AsyncWebServerRequest *request, String& message);
void processGpioArgs(AsyncWebServerRequest *request);
void buildHtml(AsyncWebServerRequest *request);
void buildAccLvlHtml(AsyncWebServerRequest *request);
void buildCredHtml(AsyncWebServerRequest *request);
void buildImportExportHtml(AsyncWebServerRequest *request);
void buildMqttConfigHtml(AsyncWebServerRequest *request);
void buildStatusHtml(AsyncWebServerRequest *request);
void buildAdvancedConfigHtml(AsyncWebServerRequest *request);
void buildNukiConfigHtml(AsyncWebServerRequest *request);
void buildGpioConfigHtml(AsyncWebServerRequest *request);
esp_err_t sendSettings(PsychicRequest *request);
bool processArgs(PsychicRequest *request, String& message);
bool processImport(PsychicRequest *request, String& message);
void processGpioArgs(PsychicRequest *request);
esp_err_t buildHtml(PsychicRequest *request);
esp_err_t buildAccLvlHtml(PsychicRequest *request);
esp_err_t buildCredHtml(PsychicRequest *request);
esp_err_t buildImportExportHtml(PsychicRequest *request);
esp_err_t buildMqttConfigHtml(PsychicRequest *request);
esp_err_t buildStatusHtml(PsychicRequest *request);
esp_err_t buildAdvancedConfigHtml(PsychicRequest *request);
esp_err_t buildNukiConfigHtml(PsychicRequest *request);
esp_err_t buildGpioConfigHtml(PsychicRequest *request);
#ifndef CONFIG_IDF_TARGET_ESP32H2
void buildConfigureWifiHtml(AsyncWebServerRequest *request);
esp_err_t buildConfigureWifiHtml(PsychicRequest *request);
#endif
void buildInfoHtml(AsyncWebServerRequest *request);
void buildCustomNetworkConfigHtml(AsyncWebServerRequest *request);
void processUnpair(AsyncWebServerRequest *request, bool opener);
void processUpdate(AsyncWebServerRequest *request);
void processFactoryReset(AsyncWebServerRequest *request);
void printInputField(const char* token, const char* description, const char* value, const size_t& maxLength, const char* args, const bool& isPassword = false, const bool& showLengthRestriction = false);
void printInputField(const char* token, const char* description, const int value, size_t maxLength, const char* args);
void printCheckBox(const char* token, const char* description, const bool value, const char* htmlClass);
void printTextarea(const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false);
void printDropDown(const char *token, const char *description, const String preselectedValue, std::vector<std::pair<String, String>> options, const String className);
void buildNavigationButton(const char* caption, const char* targetPath, const char* labelText = "");
void buildNavigationMenuEntry(const char *title, const char *targetPath, const char* warningMessage = "");
esp_err_t buildInfoHtml(PsychicRequest *request);
esp_err_t buildCustomNetworkConfigHtml(PsychicRequest *request);
esp_err_t processUnpair(PsychicRequest *request, bool opener);
esp_err_t processUpdate(PsychicRequest *request);
esp_err_t processFactoryReset(PsychicRequest *request);
void printCheckBox(PsychicStreamResponse *response, const char* token, const char* description, const bool value, const char* htmlClass);
void printTextarea(PsychicStreamResponse *response, const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false);
void printDropDown(PsychicStreamResponse *response, const char *token, const char *description, const String preselectedValue, std::vector<std::pair<String, String>> options, const String className);
void buildNavigationButton(PsychicStreamResponse *response, const char* caption, const char* targetPath, const char* labelText = "");
void buildNavigationMenuEntry(PsychicStreamResponse *response, const char *title, const char *targetPath, const char* warningMessage = "");
const std::vector<std::pair<String, String>> getNetworkDetectionOptions() const;
const std::vector<std::pair<String, String>> getGpioOptions() const;
@@ -86,8 +83,8 @@ private:
String getPreselectionForGpio(const uint8_t& pin);
String pinStateToString(uint8_t value);
void printParameter(const char* description, const char* value, const char *link = "", const char *id = "");
void printParameter(PsychicStreamResponse *response, const char* description, const char* value, const char *link = "", const char *id = "");
NukiWrapper* _nuki = nullptr;
NukiOpenerWrapper* _nukiOpener = nullptr;
Gpio* _gpio = nullptr;
@@ -95,22 +92,31 @@ private:
bool _brokerConfigured = false;
bool _rebootRequired = false;
#endif
String _response;
std::vector<String> _ssidList;
std::vector<int> _rssiList;
String generateConfirmCode();
String _confirmCode = "----";
void buildConfirmHtml(AsyncWebServerRequest *request, const String &message, uint32_t redirectDelay = 5, bool redirect = false);
void buildOtaHtml(AsyncWebServerRequest *request, bool debug = false);
void buildOtaCompletedHtml(AsyncWebServerRequest *request);
void sendCss(AsyncWebServerRequest *request);
void sendFavicon(AsyncWebServerRequest *request);
void buildHtmlHeader(String additionalHeader = "");
esp_err_t buildSSIDListHtml(PsychicRequest *request);
esp_err_t buildConfirmHtml(PsychicRequest *request, const String &message, uint32_t redirectDelay = 5, bool redirect = false);
esp_err_t buildOtaHtml(PsychicRequest *request, bool debug = false);
esp_err_t buildOtaCompletedHtml(PsychicRequest *request);
esp_err_t sendCss(PsychicRequest *request);
esp_err_t sendFavicon(PsychicRequest *request);
void createSsidList();
void buildHtmlHeader(PsychicStreamResponse *response, String additionalHeader = "");
void waitAndProcess(const bool blocking, const uint32_t duration);
void handleOtaUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
esp_err_t handleOtaUpload(PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool final);
void printProgress(size_t prg, size_t sz);
void sendResponse(AsyncWebServerRequest *request);
#ifndef CONFIG_IDF_TARGET_ESP32H2
esp_err_t buildWifiConnectHtml(PsychicRequest *request);
bool processWiFi(PsychicRequest *request, String& message);
AsyncWebServer* _asyncServer = nullptr;
#endif
void printInputField(PsychicStreamResponse *response, const char* token, const char* description, const char* value, const size_t& maxLength, const char* args, const bool& isPassword = false, const bool& showLengthRestriction = false);
void printInputField(PsychicStreamResponse *response, const char* token, const char* description, const int value, size_t maxLength, const char* args);
PsychicHttpServer* _psychicServer = nullptr;
NukiNetwork* _network = nullptr;
Preferences* _preferences = nullptr;

View File

@@ -5,7 +5,7 @@
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include <esp_task_wdt.h>
#include "esp_task_wdt.h"
#include "Config.h"
#ifndef NUKI_HUB_UPDATER
@@ -19,11 +19,12 @@
#include "Logger.h"
#include "PreferencesKeys.h"
#include "RestartReason.h"
#include <AsyncTCP.h>
#include <DNSServer.h>
#include <ESPAsyncWebServer.h>
/*
#ifdef DEBUG_NUKIHUB
#include <WString.h>
#include <MycilaWebSerial.h>
#endif
*/
char log_print_buffer[1024];
@@ -55,7 +56,7 @@ int64_t restartTs = 10 * 1000 * 60000;
#endif
AsyncWebServer* asyncServer = nullptr;
PsychicHttpServer* psychicServer = nullptr;
NukiNetwork* network = nullptr;
WebCfgServer* webCfgServer = nullptr;
Preferences* preferences = nullptr;
@@ -77,7 +78,6 @@ TaskHandle_t networkTaskHandle = nullptr;
ssize_t write_fn(void* cookie, const char* buf, ssize_t size)
{
Log->write((uint8_t *)buf, (size_t)size);
return size;
}
@@ -103,7 +103,11 @@ int _log_vprintf(const char *fmt, va_list args) {
void setReroute(){
esp_log_set_vprintf(_log_vprintf);
if(preferences->getBool(preference_mqtt_log_enabled)) esp_log_level_set("*", ESP_LOG_INFO);
if(preferences->getBool(preference_mqtt_log_enabled))
{
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("mqtt", ESP_LOG_NONE);
}
else
{
esp_log_level_set("*", ESP_LOG_DEBUG);
@@ -372,8 +376,11 @@ void setupTasks(bool ota)
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1);
esp_task_wdt_add(networkTaskHandle);
#ifndef NUKI_HUB_UPDATER
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 0);
esp_task_wdt_add(nukiTaskHandle);
if(!network->isApOpen())
{
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 0);
esp_task_wdt_add(nukiTaskHandle);
}
#endif
}
}
@@ -381,6 +388,7 @@ void setupTasks(bool ota)
void setup()
{
esp_log_level_set("*", ESP_LOG_ERROR);
esp_log_level_set("mqtt", ESP_LOG_NONE);
Serial.begin(115200);
Log = &Serial;
@@ -424,11 +432,11 @@ void setup()
if(!doOta)
{
asyncServer = new AsyncWebServer(80);
webCfgServer = new WebCfgServer(network, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, asyncServer);
psychicServer = new PsychicHttpServer;
webCfgServer = new WebCfgServer(network, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer);
webCfgServer->initialize();
asyncServer->onNotFound([](AsyncWebServerRequest* request) { request->redirect("/"); });
asyncServer->begin();
psychicServer->listen(80);
psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/"); });
}
#else
Log->print(F("Nuki Hub version "));
@@ -447,7 +455,6 @@ void setup()
}
char16_t buffer_size = preferences->getInt(preference_buffer_size, 4096);
CharBuffer::initialize(buffer_size);
gpio = new Gpio(preferences);
@@ -455,22 +462,30 @@ void setup()
gpio->getConfigurationText(gpioDesc, gpio->pinConfiguration(), "\n\r");
Log->print(gpioDesc.c_str());
const String mqttLockPath = preferences->getString(preference_mqtt_lock_path);
network = new NukiNetwork(preferences, gpio, mqttLockPath, CharBuffer::get(), buffer_size);
network->initialize();
lockEnabled = preferences->getBool(preference_lock_enabled);
openerEnabled = preferences->getBool(preference_opener_enabled);
if(network->isApOpen())
{
forceEnableWebServer = true;
doOta = false;
lockEnabled = false;
openerEnabled = false;
}
bleScanner = new BleScanner::Scanner();
// Scan interval and window according to Nuki recommendations:
// https://developer.nuki.io/t/bluetooth-specification-questions/1109/27
bleScanner->initialize("NukiHub", true, 40, 40);
bleScanner->setScanDuration(0);
lockEnabled = preferences->getBool(preference_lock_enabled);
openerEnabled = preferences->getBool(preference_opener_enabled);
const String mqttLockPath = preferences->getString(preference_mqtt_lock_path);
nukiOfficial = new NukiOfficial(preferences);
network = new NukiNetwork(preferences, gpio, mqttLockPath, CharBuffer::get(), buffer_size);
network->initialize();
networkLock = new NukiNetworkLock(network, nukiOfficial, preferences, CharBuffer::get(), buffer_size);
networkLock->initialize();
@@ -498,15 +513,20 @@ void setup()
{
if(!doOta)
{
asyncServer = new AsyncWebServer(80);
psychicServer = new PsychicHttpServer;
psychicServer->config.max_uri_handlers = 40;
psychicServer->config.stack_size = 8192;
psychicServer->listen(80);
if(forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true))
{
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, asyncServer);
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer);
webCfgServer->initialize();
asyncServer->onNotFound([](AsyncWebServerRequest* request) { request->redirect("/"); });
psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/"); });
}
else asyncServer->onNotFound([](AsyncWebServerRequest* request) { request->redirect("/webserial"); });
/*
#ifdef DEBUG_NUKIHUB
else psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/webserial"); });
if(preferences->getBool(preference_webserial_enabled, false))
{
@@ -514,15 +534,15 @@ void setup()
WebSerial.begin(asyncServer);
WebSerial.setBuffer(1024);
}
asyncServer->begin();
#endif
*/
}
}
#endif
if(doOta) setupTasks(true);
else setupTasks(false);
#ifdef DEBUG_NUKIHUB
Log->print("Task Name\tStatus\tPrio\tHWM\tTask\tAffinity\n");
char stats_buffer[1024];

View File

@@ -1,12 +1,11 @@
#include "EthernetDevice.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
#ifndef NUKI_HUB_UPDATER
#include "../MqttTopics.h"
#include "espMqttClient.h"
#endif
#include "../RestartReason.h"
RTC_NOINIT_ATTR bool criticalEthFailure;
extern char WiFi_fallbackDetect[14];
EthernetDevice::EthernetDevice(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration, const std::string& deviceName, uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t ethtype, eth_clock_mode_t clock_mode)
: NetworkDevice(hostname, ipConfiguration),
_deviceName(deviceName),
@@ -50,54 +49,6 @@ EthernetDevice::EthernetDevice(const String &hostname,
init();
}
void EthernetDevice::init()
{
#ifndef NUKI_HUB_UPDATER
size_t caLength = _preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
size_t crtLength = _preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE);
size_t keyLength = _preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE);
_useEncryption = caLength > 1; // length is 1 when empty
if(_useEncryption)
{
Log->println(F("MQTT over TLS."));
Log->println(_ca);
_mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
_mqttClientSecure->setCACert(_ca);
if(crtLength > 1 && keyLength > 1) // length is 1 when empty
{
Log->println(F("MQTT with client certificate."));
Log->println(_cert);
Log->println(_key);
_mqttClientSecure->setCertificate(_cert);
_mqttClientSecure->setPrivateKey(_key);
}
} else
{
Log->println(F("MQTT without TLS."));
_mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
}
if(_preferences->getBool(preference_mqtt_log_enabled, false) || _preferences->getBool(preference_webserial_enabled, false))
{
MqttLoggerMode mode;
if(_preferences->getBool(preference_mqtt_log_enabled, false) && _preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::MqttAndSerialAndWeb;
else if (_preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::SerialAndWeb;
else mode = MqttLoggerMode::MqttAndSerial;
_path = new char[200];
memset(_path, 0, sizeof(_path));
String pathStr = _preferences->getString(preference_mqtt_lock_path);
pathStr.concat(mqtt_topic_log);
strcpy(_path, pathStr.c_str());
Log = new MqttLogger(*getMqttClient(), _path, mode);
}
#endif
}
const String EthernetDevice::deviceName() const
{
return _deviceName.c_str();
@@ -106,20 +57,34 @@ const String EthernetDevice::deviceName() const
void EthernetDevice::initialize()
{
delay(250);
if(criticalEthFailure)
{
criticalEthFailure = false;
Log->println(F("Failed to initialize ethernet hardware"));
Log->println("Network device has a critical failure, enable fallback to Wi-Fi and reboot.");
strcpy(WiFi_fallbackDetect, "wifi_fallback");
delay(200);
restartEsp(RestartReason::NetworkDeviceCriticalFailure);
return;
}
Log->println(F("Init Ethernet"));
if(_useSpi)
{
Log->println(F("Use SPI"));
criticalEthFailure = true;
SPI.begin(_spi_sck, _spi_miso, _spi_mosi);
_hardwareInitialized = ETH.begin(_type, _phy_addr, _cs, _irq, _rst, SPI);
criticalEthFailure = false;
}
#ifdef CONFIG_IDF_TARGET_ESP32
else
{
Log->println(F("Use RMII"));
criticalEthFailure = true;
_hardwareInitialized = ETH.begin(_type, _phy_addr, _mdc, _mdio, _power, _clock_mode);
criticalEthFailure = false;
if(!_ipConfiguration->dhcpEnabled())
{
_checkIpTs = (esp_timer_get_time() / 1000) + 2000;
@@ -130,6 +95,7 @@ void EthernetDevice::initialize()
if(_hardwareInitialized)
{
Log->println(F("Ethernet hardware Initialized"));
memset(WiFi_fallbackDetect, 0, sizeof(WiFi_fallbackDetect));
if(_useSpi && !_ipConfiguration->dhcpEnabled())
{
@@ -144,13 +110,16 @@ void EthernetDevice::initialize()
else
{
Log->println(F("Failed to initialize ethernet hardware"));
Log->println("Network device has a critical failure, enable fallback to Wi-Fi and reboot.");
strcpy(WiFi_fallbackDetect, "wifi_fallback");
delay(200);
restartEsp(RestartReason::NetworkDeviceCriticalFailure);
return;
}
}
void EthernetDevice::update()
{
NetworkDevice::update();
if(_checkIpTs != -1)
{
if(_ipConfiguration->ipAddress() != ETH.localIP())
@@ -221,17 +190,14 @@ void EthernetDevice::onNetworkEvent(arduino_event_id_t event, arduino_event_info
}
}
void EthernetDevice::reconfigure()
{
delay(200);
restartEsp(RestartReason::ReconfigureETH);
}
bool EthernetDevice::supportsEncryption()
void EthernetDevice::scan(bool passive, bool async)
{
return true;
}
bool EthernetDevice::isConnected()
@@ -239,20 +205,14 @@ bool EthernetDevice::isConnected()
return _connected;
}
ReconnectStatus EthernetDevice::reconnect(bool force)
bool EthernetDevice::isApOpen()
{
if(!_hardwareInitialized)
{
return ReconnectStatus::CriticalFailure;
}
delay(200);
return isConnected() ? ReconnectStatus::Success : ReconnectStatus::Failure;
return false;
}
void EthernetDevice::onDisconnected()
{
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
reconnect();
}
int8_t EthernetDevice::signalStrength()

View File

@@ -11,9 +11,6 @@
#include <NetworkClientSecure.h>
#include <Preferences.h>
#include "NetworkDevice.h"
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#endif
class EthernetDevice : public NetworkDevice
{
@@ -48,26 +45,23 @@ public:
virtual void initialize();
virtual void reconfigure();
virtual void update();
virtual ReconnectStatus reconnect(bool force = false);
bool supportsEncryption() override;
virtual void scan(bool passive = false, bool async = true);
virtual bool isConnected();
virtual bool isApOpen();
int8_t signalStrength() override;
String localIP() override;
String BSSIDstr() override;
private:
Preferences* _preferences;
void init();
void onDisconnected();
void onNetworkEvent(arduino_event_id_t event, arduino_event_info_t info);
bool _connected = false;
char* _path;
bool _hardwareInitialized = false;
const std::string _deviceName;
@@ -91,10 +85,4 @@ private:
eth_phy_type_t _type;
eth_clock_mode_t _clock_mode;
bool _useSpi = false;
#ifndef NUKI_HUB_UPDATER
char _ca[TLS_CA_MAX_SIZE] = {0};
char _cert[TLS_CERT_MAX_SIZE] = {0};
char _key[TLS_KEY_MAX_SIZE] = {0};
#endif
};

View File

@@ -1,179 +1,6 @@
#include <Arduino.h>
#include "NetworkDevice.h"
#include "../Logger.h"
void NetworkDevice::printError()
{
Log->print(F("Free Heap: "));
Log->println(ESP.getFreeHeap());
}
#ifndef NUKI_HUB_UPDATER
void NetworkDevice::update()
{
if (_mqttEnabled)
{
getMqttClient()->loop();
}
}
void NetworkDevice::mqttSetClientId(const char *clientId)
{
if (_useEncryption)
{
_mqttClientSecure->setClientId(clientId);
}
else
{
_mqttClient->setClientId(clientId);
}
}
void NetworkDevice::mqttSetCleanSession(bool cleanSession)
{
if (_useEncryption)
{
_mqttClientSecure->setCleanSession(cleanSession);
}
else
{
_mqttClient->setCleanSession(cleanSession);
}
}
void NetworkDevice::mqttSetKeepAlive(uint16_t keepAlive)
{
if (_useEncryption)
{
_mqttClientSecure->setKeepAlive(keepAlive);
}
else
{
_mqttClient->setKeepAlive(keepAlive);
}
}
uint16_t NetworkDevice::mqttPublish(const char *topic, uint8_t qos, bool retain, const char *payload)
{
return getMqttClient()->publish(topic, qos, retain, payload);
}
uint16_t NetworkDevice::mqttPublish(const char *topic, uint8_t qos, bool retain, const uint8_t *payload, size_t length)
{
return getMqttClient()->publish(topic, qos, retain, payload, length);
}
bool NetworkDevice::mqttConnected() const
{
return getMqttClient()->connected();
}
void NetworkDevice::mqttSetServer(const char *host, uint16_t port)
{
if (_useEncryption)
{
_mqttClientSecure->setServer(host, port);
}
else
{
_mqttClient->setServer(host, port);
}
}
bool NetworkDevice::mqttConnect()
{
return getMqttClient()->connect();
}
bool NetworkDevice::mqttDisconnect(bool force)
{
return getMqttClient()->disconnect(force);
}
void NetworkDevice::setWill(const char *topic, uint8_t qos, bool retain, const char *payload)
{
if (_useEncryption)
{
_mqttClientSecure->setWill(topic, qos, retain, payload);
}
else
{
_mqttClient->setWill(topic, qos, retain, payload);
}
}
void NetworkDevice::mqttSetCredentials(const char *username, const char *password)
{
if (_useEncryption)
{
_mqttClientSecure->setCredentials(username, password);
}
else
{
_mqttClient->setCredentials(username, password);
}
}
void NetworkDevice::mqttOnMessage(espMqttClientTypes::OnMessageCallback callback)
{
if (_useEncryption)
{
_mqttClientSecure->onMessage(callback);
}
else
{
_mqttClient->onMessage(callback);
}
}
void NetworkDevice::mqttOnConnect(espMqttClientTypes::OnConnectCallback callback)
{
if(_useEncryption)
{
_mqttClientSecure->onConnect(callback);
}
else
{
_mqttClient->onConnect(callback);
}
}
void NetworkDevice::mqttOnDisconnect(espMqttClientTypes::OnDisconnectCallback callback)
{
if (_useEncryption)
{
_mqttClientSecure->onDisconnect(callback);
}
else
{
_mqttClient->onDisconnect(callback);
}
}
uint16_t NetworkDevice::mqttSubscribe(const char *topic, uint8_t qos)
{
return getMqttClient()->subscribe(topic, qos);
}
void NetworkDevice::disableMqtt()
{
getMqttClient()->disconnect();
_mqttEnabled = false;
}
MqttClient *NetworkDevice::getMqttClient() const
{
if (_useEncryption)
{
return _mqttClientSecure;
}
else
{
return _mqttClient;
}
}
#else
void NetworkDevice::update()
{
}
#endif
}

View File

@@ -1,18 +1,6 @@
#pragma once
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#include "MqttClientSetup.h"
#endif
#include "IPConfiguration.h"
enum class ReconnectStatus
{
Failure = 0,
Success = 1,
CriticalFailure = 2
};
class NetworkDevice
{
public:
@@ -24,50 +12,17 @@ public:
virtual const String deviceName() const = 0;
virtual void initialize() = 0;
virtual ReconnectStatus reconnect(bool force = false) = 0;
virtual void reconfigure() = 0;
virtual void printError();
virtual bool supportsEncryption() = 0;
virtual void update();
virtual void scan(bool passive = false, bool async = true) = 0;
virtual bool isConnected() = 0;
virtual bool isApOpen() = 0;
virtual int8_t signalStrength() = 0;
virtual String localIP() = 0;
virtual String BSSIDstr() = 0;
#ifndef NUKI_HUB_UPDATER
virtual void mqttSetClientId(const char* clientId);
virtual void mqttSetCleanSession(bool cleanSession);
virtual void mqttSetKeepAlive(uint16_t keepAlive);
virtual uint16_t mqttPublish(const char* topic, uint8_t qos, bool retain, const char* payload);
virtual uint16_t mqttPublish(const char* topic, uint8_t qos, bool retain, const uint8_t* payload, size_t length);
virtual bool mqttConnected() const;
virtual void mqttSetServer(const char* host, uint16_t port);
virtual bool mqttConnect();
virtual bool mqttDisconnect(bool force);
virtual void setWill(const char* topic, uint8_t qos, bool retain, const char* payload);
virtual void mqttSetCredentials(const char* username, const char* password);
virtual void mqttOnMessage(espMqttClientTypes::OnMessageCallback callback);
virtual void mqttOnConnect(espMqttClientTypes::OnConnectCallback callback);
virtual void mqttOnDisconnect(espMqttClientTypes::OnDisconnectCallback callback);
virtual void disableMqtt();
virtual uint16_t mqttSubscribe(const char* topic, uint8_t qos);
#endif
protected:
#ifndef NUKI_HUB_UPDATER
espMqttClient *_mqttClient = nullptr;
espMqttClientSecure *_mqttClientSecure = nullptr;
bool _useEncryption = false;
bool _mqttEnabled = true;
MqttClient *getMqttClient() const;
#endif
protected:
const String _hostname;
const IPConfiguration* _ipConfiguration = nullptr;
};

View File

@@ -1,66 +1,14 @@
#include "esp_wifi.h"
#include <WiFi.h>
#include "WifiDevice.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
#ifndef NUKI_HUB_UPDATER
#include "../MqttTopics.h"
#include "espMqttClient.h"
#endif
#include "../RestartReason.h"
RTC_NOINIT_ATTR char WiFiDevice_reconfdetect[17];
WifiDevice::WifiDevice(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration)
: NetworkDevice(hostname, ipConfiguration),
_preferences(preferences),
_wm(preferences->getString(preference_cred_user, "").c_str(), preferences->getString(preference_cred_password, "").c_str())
_preferences(preferences)
{
_startAp = strcmp(WiFiDevice_reconfdetect, "reconfigure_wifi") == 0;
#ifndef NUKI_HUB_UPDATER
size_t caLength = preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
size_t crtLength = preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE);
size_t keyLength = preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE);
_useEncryption = caLength > 1; // length is 1 when empty
if(_useEncryption)
{
Log->println(F("MQTT over TLS."));
Log->println(_ca);
_mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
_mqttClientSecure->setCACert(_ca);
if(crtLength > 1 && keyLength > 1) // length is 1 when empty
{
Log->println(F("MQTT with client certificate."));
Log->println(_cert);
Log->println(_key);
_mqttClientSecure->setCertificate(_cert);
_mqttClientSecure->setPrivateKey(_key);
}
} else
{
Log->println(F("MQTT without TLS."));
_mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
}
if(preferences->getBool(preference_mqtt_log_enabled, false) || preferences->getBool(preference_webserial_enabled, false))
{
MqttLoggerMode mode;
if(preferences->getBool(preference_mqtt_log_enabled, false) && preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::MqttAndSerialAndWeb;
else if (preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::SerialAndWeb;
else mode = MqttLoggerMode::MqttAndSerial;
_path = new char[200];
memset(_path, 0, sizeof(_path));
String pathStr = preferences->getString(preference_mqtt_lock_path);
pathStr.concat(mqtt_topic_log);
strcpy(_path, pathStr.c_str());
Log = new MqttLogger(*getMqttClient(), _path, mode);
}
#endif
}
const String WifiDevice::deviceName() const
@@ -70,128 +18,390 @@ const String WifiDevice::deviceName() const
void WifiDevice::initialize()
{
std::vector<const char *> wm_menu;
wm_menu.push_back("wifi");
wm_menu.push_back("exit");
_wm.setEnableConfigPortal(_startAp || !_preferences->getBool(preference_network_wifi_fallback_disabled, false));
// reduced timeout if ESP is set to restart on disconnect
_wm.setFindBestRSSI(_preferences->getBool(preference_find_best_rssi));
_wm.setConnectTimeout(20);
_wm.setConfigPortalTimeout(_preferences->getBool(preference_restart_on_disconnect, false) ? 60 * 3 : 60 * 30);
_wm.setShowInfoUpdate(false);
_wm.setMenu(wm_menu);
_wm.setHostname(_hostname);
String ssid = _preferences->getString(preference_wifi_ssid, "");
String pass = _preferences->getString(preference_wifi_pass, "");
WiFi.setHostname(_hostname.c_str());
if(!_ipConfiguration->dhcpEnabled())
{
_wm.setSTAStaticIPConfig(_ipConfiguration->ipAddress(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet(), _ipConfiguration->dnsServer());
}
_wm.setAPCallback(clearRtcInitVar);
bool res = false;
bool connectedFromPortal = false;
if(_startAp)
{
Log->println(F("Opening Wi-Fi configuration portal."));
res = _wm.startConfigPortal();
connectedFromPortal = true;
}
else
{
res = _wm.autoConnect(); // password protected ap
}
if(!res)
{
esp_wifi_disconnect();
esp_wifi_stop();
esp_wifi_deinit();
Log->println(F("Failed to connect. Wait for ESP restart."));
delay(1000);
restartEsp(RestartReason::WifiInitFailed);
}
else {
Log->print(F("Wi-Fi connected: "));
Log->println(WiFi.localIP().toString());
if(connectedFromPortal)
{
Log->println(F("Connected using WifiManager portal. Wait for ESP restart."));
delay(1000);
restartEsp(RestartReason::ConfigurationUpdated);
}
WiFi.config(_ipConfiguration->ipAddress(), _ipConfiguration->dnsServer(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet());
}
WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info)
{
if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
{
onDisconnected();
if(!_openAP && !_connecting && _connected)
{
onDisconnected();
}
}
else if(event == ARDUINO_EVENT_WIFI_STA_GOT_IP)
else if(event == ARDUINO_EVENT_WIFI_STA_CONNECTED)
{
onConnected();
}
else if(event == ARDUINO_EVENT_WIFI_SCAN_DONE)
{
Log->println(F("Wi-Fi scan done"));
_foundNetworks = WiFi.scanComplete();
for (int i = 0; i < _foundNetworks; i++)
{
Log->println(String(F("SSID ")) + WiFi.SSID(i) + String(F(" found with RSSI: ")) +
String(WiFi.RSSI(i)) + String(F("(")) +
String(constrain((100.0 + WiFi.RSSI(i)) * 2, 0, 100)) +
String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(i) +
String(F(" and channel: ")) + String(WiFi.channel(i)));
}
if (_connectOnScanDone && _foundNetworks > 0)
{
connect();
}
else if (_connectOnScanDone)
{
Log->println("No networks found, restarting scan");
scan(false, true);
}
else if (_openAP)
{
openAP();
}
else if(_convertOldWiFi)
{
Log->println("Trying to convert old WiFi settings");
_convertOldWiFi = false;
_preferences->putBool(preference_wifi_converted, true);
wifi_config_t wifi_cfg;
if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
Log->println("Failed to get Wi-Fi configuration in RAM");
}
if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {
Log->println("Failed to set storage Wi-Fi");
}
String tempSSID = String(reinterpret_cast<const char*>(wifi_cfg.sta.ssid));
String tempPass = String(reinterpret_cast<const char*>(wifi_cfg.sta.password));
tempSSID.trim();
tempPass.trim();
bool found = false;
for (int i = 0; i < _foundNetworks; i++)
{
if(tempSSID.length() > 0 && tempSSID == WiFi.SSID(i) && tempPass.length() > 0)
{
_preferences->putString(preference_wifi_ssid, tempSSID);
_preferences->putString(preference_wifi_pass, tempPass);
Log->println("Succesfully converted old WiFi settings");
found = true;
break;
}
}
memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
Log->println("Failed to clear NVS Wi-Fi configuration");
}
if(found)
{
Log->println(String("Attempting to connect to saved SSID ") + String(ssid));
_connectOnScanDone = true;
_openAP = false;
scan(false, true);
return;
}
else
{
Log->println("No SSID or Wifi password saved, opening AP");
_connectOnScanDone = false;
_openAP = true;
scan(false, true);
return;
}
}
}
});
ssid.trim();
pass.trim();
if(ssid.length() > 0 && pass.length() > 0)
{
Log->println(String("Attempting to connect to saved SSID ") + String(ssid));
_connectOnScanDone = true;
_openAP = false;
scan(false, true);
return;
}
else if(!_preferences->getBool(preference_wifi_converted, false))
{
_connectOnScanDone = false;
_openAP = false;
_convertOldWiFi = true;
scan(false, true);
return;
}
else
{
Log->println("No SSID or Wifi password saved, opening AP");
_connectOnScanDone = false;
_openAP = true;
scan(false, true);
return;
}
}
void WifiDevice::scan(bool passive, bool async)
{
WiFi.scanDelete();
if(async)
{
Log->println(F("Wi-Fi async scan started"));
}
else
{
Log->println(F("Wi-Fi sync scan started"));
}
if(passive)
{
WiFi.scanNetworks(async,false,true,75U);
}
else
{
WiFi.scanNetworks(async);
}
}
void WifiDevice::openAP()
{
if(_startAP)
{
WiFi.persistent(false);
WiFi.mode(WIFI_AP_STA);
WiFi.persistent(false);
WiFi.softAPsetHostname(_hostname.c_str());
WiFi.softAP("NukiHub", "NukiHubESP32");
WiFi.persistent(false);
_startAP = false;
}
}
bool WifiDevice::connect()
{
bool ret = false;
String ssid = _preferences->getString(preference_wifi_ssid, "");
String pass = _preferences->getString(preference_wifi_pass, "");
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.setHostname(_hostname.c_str());
delay(500);
int bestConnection = -1;
for (int i = 0; i < _foundNetworks; i++)
{
if (ssid == WiFi.SSID(i))
{
Log->println(String(F("Saved SSID ")) + ssid + String(F(" found with RSSI: ")) +
String(WiFi.RSSI(i)) + String(F("(")) +
String(constrain((100.0 + WiFi.RSSI(i)) * 2, 0, 100)) +
String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(i) +
String(F(" and channel: ")) + String(WiFi.channel(i)));
if (bestConnection == -1)
{
bestConnection = i;
}
else
{
if (WiFi.RSSI(i) > WiFi.RSSI(bestConnection))
{
bestConnection = i;
}
}
}
}
if (bestConnection == -1)
{
Log->print("No network found with SSID: ");
Log->println(ssid);
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
_connectOnScanDone = true;
_openAP = false;
scan(false, true);
return false;
}
else
{
_connecting = true;
Log->println(String(F("Trying to connect to SSID ")) + ssid + String(F(" found with RSSI: ")) +
String(WiFi.RSSI(bestConnection)) + String(F("(")) +
String(constrain((100.0 + WiFi.RSSI(bestConnection)) * 2, 0, 100)) +
String(F(" %) and BSSID: ")) + WiFi.BSSIDstr(bestConnection) +
String(F(" and channel: ")) + String(WiFi.channel(bestConnection)));
ret = WiFi.begin(ssid.c_str(), pass.c_str(), WiFi.channel(bestConnection), WiFi.BSSID(bestConnection), true);
WiFi.persistent(false);
_connecting = false;
}
if(!ret)
{
int loop = 0;
while(!isConnected() && loop < 200)
{
loop++;
delay(100);
}
if(!isConnected())
{
esp_wifi_disconnect();
esp_wifi_stop();
esp_wifi_deinit();
Log->println(F("Failed to connect. Wait for ESP restart."));
delay(1000);
restartEsp(RestartReason::WifiInitFailed);
}
}
else
{
if(!_preferences->getBool(preference_wifi_converted, false))
{
_preferences->putBool(preference_wifi_converted, true);
}
int loop = 0;
while(!isConnected() && loop < 200)
{
loop++;
delay(100);
}
if(!isConnected())
{
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000))
{
restartEsp(RestartReason::RestartOnDisconnectWatchdog);
return false;
}
Log->print("Connection failed, retrying");
_connectOnScanDone = true;
_openAP = false;
scan(false, true);
return false;
}
}
return ret;
}
void WifiDevice::reconfigure()
{
strcpy(WiFiDevice_reconfdetect, "reconfigure_wifi");
bool changed = false;
wifi_config_t wifi_cfg;
if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
Log->println("Failed to get Wi-Fi configuration in RAM");
}
if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {
Log->println("Failed to set storage Wi-Fi");
}
if(sizeof(wifi_cfg.sta.ssid) > 0)
{
memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
changed = true;
}
if(sizeof(wifi_cfg.sta.password) > 0)
{
memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
changed = true;
}
if(changed)
{
if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
Log->println("Failed to clear NVS Wi-Fi configuration");
}
}
_preferences->putString(preference_wifi_ssid, "");
_preferences->putString(preference_wifi_pass, "");
delay(200);
restartEsp(RestartReason::ReconfigureWifi);
}
bool WifiDevice::supportsEncryption()
{
return true;
}
bool WifiDevice::isConnected()
{
return WiFi.isConnected();
}
ReconnectStatus WifiDevice::reconnect(bool force)
{
_wm.setFindBestRSSI(_preferences->getBool(preference_find_best_rssi));
if((!isConnected() || force) && !_isReconnecting)
{
_isReconnecting = true;
WiFi.disconnect();
int loop = 0;
while(isConnected() && loop <20)
{
delay(100);
loop++;
}
_wm.resetScan();
_wm.autoConnect();
_isReconnecting = false;
}
if(!isConnected() && _disconnectTs > (esp_timer_get_time() / 1000) - 120000) _wm.setEnableConfigPortal(_startAp || !_preferences->getBool(preference_network_wifi_fallback_disabled, false));
return isConnected() ? ReconnectStatus::Success : ReconnectStatus::Failure;
return (WiFi.status() == WL_CONNECTED);
}
void WifiDevice::onConnected()
{
_isReconnecting = false;
_wm.setEnableConfigPortal(_startAp || !_preferences->getBool(preference_network_wifi_fallback_disabled, false));
Log->println(F("Wi-Fi connected"));
_connectedChannel = WiFi.channel();
_connectedBSSID = WiFi.BSSID();
_connected = true;
}
void WifiDevice::onDisconnected()
{
_disconnectTs = (esp_timer_get_time() / 1000);
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
_wm.setEnableConfigPortal(false);
reconnect();
if(_connected)
{
_connected = false;
_disconnectTs = (esp_timer_get_time() / 1000);
Log->println(F("Wi-Fi disconnected"));
//QUICK RECONNECT
_connecting = true;
String ssid = _preferences->getString(preference_wifi_ssid, "");
String pass = _preferences->getString(preference_wifi_pass, "");
WiFi.begin(ssid.c_str(), pass.c_str(), _connectedChannel, _connectedBSSID, true);
WiFi.persistent(false);
int loop = 0;
while(!isConnected() && loop < 50)
{
loop++;
delay(100);
}
_connecting = false;
//END QUICK RECONECT
if(!isConnected())
{
if(_preferences->getBool(preference_restart_on_disconnect, false) && ((esp_timer_get_time() / 1000) > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
WiFi.persistent(false);
WiFi.disconnect(true);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(500);
wifi_mode_t wifiMode;
esp_wifi_get_mode(&wifiMode);
while (wifiMode != WIFI_MODE_STA || WiFi.status() == WL_CONNECTED)
{
delay(500);
Log->println(F("Waiting for WiFi mode change or disconnection."));
esp_wifi_get_mode(&wifiMode);
}
_connectOnScanDone = true;
_openAP = false;
scan(false, true);
}
}
}
int8_t WifiDevice::signalStrength()
@@ -209,7 +419,7 @@ String WifiDevice::BSSIDstr()
return WiFi.BSSIDstr();
}
void WifiDevice::clearRtcInitVar(WiFiManager *)
bool WifiDevice::isApOpen()
{
memset(WiFiDevice_reconfdetect, 0, sizeof WiFiDevice_reconfdetect);
}
return _openAP;
}

View File

@@ -4,10 +4,6 @@
#include <NetworkClientSecure.h>
#include <Preferences.h>
#include "NetworkDevice.h"
#include "WiFiManager.h"
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#endif
#include "IPConfiguration.h"
class WifiDevice : public NetworkDevice
@@ -19,33 +15,32 @@ public:
virtual void initialize();
virtual void reconfigure();
virtual ReconnectStatus reconnect(bool force = false);
bool supportsEncryption() override;
virtual void scan(bool passive = false, bool async = true);
virtual bool isConnected();
virtual bool isApOpen();
int8_t signalStrength() override;
String localIP() override;
String BSSIDstr() override;
private:
static void clearRtcInitVar(WiFiManager*);
void openAP();
void onDisconnected();
void onConnected();
bool connect();
WiFiManager _wm;
Preferences* _preferences = nullptr;
bool _startAp = false;
bool _isReconnecting = false;
char* _path;
int _foundNetworks = 0;
int _disconnectCount = 0;
bool _connectOnScanDone = false;
bool _connecting = false;
bool _openAP = false;
bool _startAP = true;
bool _convertOldWiFi = false;
bool _connected = false;
uint8_t _connectedChannel = 0;
uint8_t* _connectedBSSID;
int64_t _disconnectTs = 0;
#ifndef NUKI_HUB_UPDATER
char _ca[TLS_CA_MAX_SIZE] = {0};
char _cert[TLS_CERT_MAX_SIZE] = {0};
char _key[TLS_KEY_MAX_SIZE] = {0};
#endif
};