Merge branch 'master' into check-keypad-codes

This commit is contained in:
iranl
2024-11-02 19:41:11 +01:00
committed by GitHub
115 changed files with 9966 additions and 962 deletions

View File

@@ -4,7 +4,7 @@
#define NUKI_HUB_VERSION "9.02"
#define NUKI_HUB_BUILD "unknownbuildnr"
#define NUKI_HUB_DATE "2024-10-28"
#define NUKI_HUB_DATE "2024-11-01"
#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"
@@ -110,11 +110,9 @@
#define MQTT_QOS_LEVEL 1
#define MQTT_CLEAN_SESSIONS false
#define MQTT_KEEP_ALIVE 60
#define MQTT_STACK_SIZE 12288
#define GPIO_DEBOUNCE_TIME 200
#define CHAR_BUFFER_SIZE 4096
#define NUKI_TASK_SIZE 8192
#define PD_TASK_SIZE 1024
#define MAX_AUTHLOG 5
#define MAX_KEYPAD 10
#define MAX_TIMECONTROL 10
@@ -122,3 +120,4 @@
#endif
#define NETWORK_TASK_SIZE 12288
#define HTTPD_TASK_SIZE 8192

View File

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

View File

@@ -1,28 +1,28 @@
#pragma once
#define mqtt_topic_lock_action "/lock/action"
#define mqtt_topic_lock_status_updated "/lock/statusUpdated"
#define mqtt_topic_lock_state "/lock/state"
#define mqtt_topic_lock_ha_state "/lock/hastate"
#define mqtt_topic_lock_json "/lock/json"
#define mqtt_topic_lock_binary_state "/lock/binaryState"
#define mqtt_topic_lock_continuous_mode "/lock/continuousMode"
#define mqtt_topic_lock_ring "/lock/ring"
#define mqtt_topic_lock_binary_ring "/lock/binaryRing"
#define mqtt_topic_lock_trigger "/lock/trigger"
#define mqtt_topic_lock_last_lock_action "/lock/lastLockAction"
#define mqtt_topic_lock_log "/lock/log"
#define mqtt_topic_lock_log_latest "/lock/shortLog"
#define mqtt_topic_lock_log_rolling "/lock/rollingLog"
#define mqtt_topic_lock_log_rolling_last "/lock/lastRollingLog"
#define mqtt_topic_lock_auth_id "/lock/authorizationId"
#define mqtt_topic_lock_auth_name "/lock/authorizationName"
#define mqtt_topic_lock_completionStatus "/lock/completionStatus"
#define mqtt_topic_lock_action_command_result "/lock/commandResult"
#define mqtt_topic_lock_door_sensor_state "/lock/doorSensorState"
#define mqtt_topic_lock_rssi "/lock/rssi"
#define mqtt_topic_lock_address "/lock/address"
#define mqtt_topic_lock_retry "/lock/retry"
#define mqtt_topic_lock_action "/action"
#define mqtt_topic_lock_status_updated "/statusUpdated"
#define mqtt_topic_lock_state "/state"
#define mqtt_topic_lock_ha_state "/hastate"
#define mqtt_topic_lock_json "/json"
#define mqtt_topic_lock_binary_state "/binaryState"
#define mqtt_topic_lock_continuous_mode "/continuousMode"
#define mqtt_topic_lock_ring "/ring"
#define mqtt_topic_lock_binary_ring "/binaryRing"
#define mqtt_topic_lock_trigger "/trigger"
#define mqtt_topic_lock_last_lock_action "/lastLockAction"
#define mqtt_topic_lock_log "/log"
#define mqtt_topic_lock_log_latest "/shortLog"
#define mqtt_topic_lock_log_rolling "/rollingLog"
#define mqtt_topic_lock_log_rolling_last "/lastRollingLog"
#define mqtt_topic_lock_auth_id "/authorizationId"
#define mqtt_topic_lock_auth_name "/authorizationName"
#define mqtt_topic_lock_completionStatus "/completionStatus"
#define mqtt_topic_lock_action_command_result "/commandResult"
#define mqtt_topic_lock_door_sensor_state "/doorSensorState"
#define mqtt_topic_lock_rssi "/rssi"
#define mqtt_topic_lock_address "/address"
#define mqtt_topic_lock_retry "/retry"
#define mqtt_topic_official_lock_action "/lockAction"
//#define mqtt_topic_official_mode "/mode"
@@ -49,11 +49,11 @@
#define mqtt_topic_config_single_lock "/configuration/singleLock"
#define mqtt_topic_config_sound_level "/configuration/soundLevel"
#define mqtt_topic_query_config "/lock/query/config"
#define mqtt_topic_query_lockstate "/lock/query/lockstate"
#define mqtt_topic_query_keypad "/lock/query/keypad"
#define mqtt_topic_query_battery "/lock/query/battery"
#define mqtt_topic_query_lockstate_command_result "/lock/query/lockstateCommandResult"
#define mqtt_topic_query_config "/query/config"
#define mqtt_topic_query_lockstate "/query/lockstate"
#define mqtt_topic_query_keypad "/query/keypad"
#define mqtt_topic_query_battery "/query/battery"
#define mqtt_topic_query_lockstate_command_result "/query/lockstateCommandResult"
#define mqtt_topic_battery_level "/battery/level"
#define mqtt_topic_battery_critical "/battery/critical"
@@ -110,9 +110,7 @@
#define mqtt_topic_restart_reason_esp "/maintenance/restartReasonNukiEsp"
#define mqtt_topic_mqtt_connection_state "/maintenance/mqttConnectionState"
#define mqtt_topic_network_device "/maintenance/networkDevice"
#define mqtt_hybrid_state "/maintenance/hybridConnected"
#define mqtt_topic_presence "/presence/devices"
#define mqtt_hybrid_state "/hybridConnected"
#define mqtt_topic_gpio_prefix "/gpio"
#define mqtt_topic_gpio_pin "/pin_"

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,6 @@
#ifndef NUKI_HUB_UPDATER
#include "MqttReceiver.h"
#include "mqtt_client.h"
#include "MqttTopics.h"
#include "Gpio.h"
#include <ArduinoJson.h>
@@ -28,6 +27,7 @@ public:
void scan(bool passive = false, bool async = true);
bool isApOpen();
bool isConnected();
bool wifiConnected();
void clearWifiFallback();
const String networkDeviceName() const;
@@ -55,7 +55,7 @@ public:
void publishULong(const char* prefix, const char* topic, const unsigned long value, bool retain);
void publishLongLong(const char* prefix, const char* topic, int64_t value, bool retain);
void publishBool(const char* prefix, const char* topic, const bool value, bool retain);
bool publishString(const char* prefix, const char* topic, const char* value, bool retain);
void publishString(const char* prefix, const char* topic, const char* value, bool retain);
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const char* availabilityTopic, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction);
void publishHASSConfigAdditionalLockEntities(char* deviceType, const char* baseTopic, char* name, char* uidString);
@@ -91,7 +91,6 @@ public:
bool mqttRecentlyConnected();
bool pathEquals(const char* prefix, const char* path, const char* referencePath);
uint16_t subscribe(const char* topic, uint8_t qos);
void addReconnectedCallback(std::function<void()> reconnectedCallback);
#endif
private:
@@ -106,8 +105,8 @@ private:
IPConfiguration* _ipConfiguration = nullptr;
String _hostname;
char _hostnameArr[101] = {0};
char _nukiHubPath[181] = {0};
NetworkDevice* _device = nullptr;
std::function<void()> _keepAliveCallback = nullptr;
std::vector<std::function<void()>> _reconnectedCallbacks;
@@ -118,10 +117,11 @@ private:
bool _offEnabled = false;
#ifndef NUKI_HUB_UPDATER
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);
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 onMqttConnect(const bool& sessionPresent);
void onMqttDisconnect(const espMqttClientTypes::DisconnectReason& reason);
void parseGpioTopics(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total);
void gpioActionCallback(const GpioAction& action, const int& pin);
String createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
@@ -144,23 +144,17 @@ private:
char _mqttConnectionStateTopic[211] = {0};
String _lockPath;
String _discoveryTopic;
String _brokerAddr;
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};
char _mqttUser[31] = {0};
@@ -170,6 +164,7 @@ private:
int _networkTimeout = 0;
std::vector<MqttReceiver*> _mqttReceivers;
bool _restartOnDisconnect = false;
bool _disableNetworkIfNotConnected = false;
bool _checkUpdates = false;
bool _firstConnect = true;
bool _publishDebugInfo = false;
@@ -177,6 +172,7 @@ private:
std::vector<String> _subscribedTopics;
std::map<String, String> _initTopics;
int64_t _lastConnectedTs = 0;
int64_t _lastMQTTConnectionAttemptTs = 0;
int64_t _lastMaintenanceTs = 0;
int64_t _lastUpdateCheckTs = 0;
int64_t _lastRssiTs = 0;

View File

@@ -37,18 +37,12 @@ NukiNetworkLock::~NukiNetworkLock()
void NukiNetworkLock::initialize()
{
String mqttPath = _preferences->getString(preference_mqtt_lock_path, "");
if(mqttPath.length() > 0)
mqttPath.concat("/lock");
size_t len = mqttPath.length();
for(int i=0; i < len; i++)
{
size_t len = mqttPath.length();
for(int i=0; i < len; i++)
{
_mqttPath[i] = mqttPath.charAt(i);
}
}
else
{
strcpy(_mqttPath, "nuki");
_preferences->putString(preference_mqtt_lock_path, _mqttPath);
_mqttPath[i] = mqttPath.charAt(i);
}
_haEnabled = _preferences->getString(preference_mqtt_hass_discovery, "") != "";
@@ -58,18 +52,6 @@ void NukiNetworkLock::initialize()
_network->subscribe(_mqttPath, mqtt_topic_lock_action);
_network->initTopic(_mqttPath, mqtt_topic_config_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_config_action);
_network->subscribe(_mqttPath, mqtt_topic_reset);
_network->initTopic(_mqttPath, mqtt_topic_reset, "0");
if(_preferences->getBool(preference_update_from_mqtt, false))
{
_network->subscribe(_mqttPath, mqtt_topic_update);
_network->initTopic(_mqttPath, mqtt_topic_update, "0");
}
_network->subscribe(_mqttPath, mqtt_topic_webserver_action);
_network->initTopic(_mqttPath, mqtt_topic_webserver_action, "--");
_network->initTopic(_mqttPath, mqtt_topic_webserver_state, (_preferences->getBool(preference_webserver_enabled, true) || forceEnableWebServer ? "1" : "0"));
_network->initTopic(_mqttPath, mqtt_topic_query_config, "0");
_network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0");
@@ -100,7 +82,6 @@ void NukiNetworkLock::initialize()
_network->removeTopic(_mqttPath, mqtt_topic_battery_max_turn_current);
_network->removeTopic(_mqttPath, mqtt_topic_battery_lock_distance);
_network->removeTopic(_mqttPath, mqtt_topic_battery_keypad_critical);
//_network->removeTopic(_mqttPath, mqtt_topic_presence);
}
if(!_preferences->getBool(preference_conf_info_enabled, true))
@@ -119,34 +100,34 @@ void NukiNetworkLock::initialize()
{
if(!_disableNonJSON)
{
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_action);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_id);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_name);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_code);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_enabled);
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_action, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_id, "0");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_name, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_code, "000000");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_enabled, "1");
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_action);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_id);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_name);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_code);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_enabled);
}
_network->subscribe(_mqttPath, mqtt_topic_query_keypad);
_network->subscribe(_mqttPath, mqtt_topic_keypad_json_action);
_network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
_network->initTopic(_mqttPath, mqtt_topic_keypad_json_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_query_keypad);
_network->subscribe(_mqttPath, mqtt_topic_keypad_json_action);
}
if(_preferences->getBool(preference_timecontrol_control_enabled))
{
_network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
}
if(_preferences->getBool(preference_auth_control_enabled))
{
_network->subscribe(_mqttPath, mqtt_topic_auth_action);
_network->initTopic(_mqttPath, mqtt_topic_auth_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_auth_action);
}
if(_nukiOfficial->getOffEnabled())
@@ -163,7 +144,7 @@ void NukiNetworkLock::initialize()
{
_network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last);
}
_network->addReconnectedCallback([&]()
{
_reconnected = true;
@@ -178,8 +159,10 @@ void NukiNetworkLock::update()
}
}
void NukiNetworkLock::onMqttDataReceived(char* topic, int topic_len, char* data, int data_len)
void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
{
char* data = (char*)payload;
if(_network->mqttRecentlyConnected() && _network->pathEquals(_mqttPath, mqtt_topic_lock_action, topic))
{
Log->println("MQTT recently connected, ignoring lock action.");
@@ -445,22 +428,22 @@ void NukiNetworkLock::onMqttDataReceived(char* topic, int topic_len, char* data,
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_CONFIG;
publishString(mqtt_topic_query_config, "0", true);
publishInt(mqtt_topic_query_config, 0, true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_LOCKSTATE;
publishString(mqtt_topic_query_lockstate, "0", true);
publishInt(mqtt_topic_query_lockstate, 0, true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_KEYPAD;
publishString(mqtt_topic_query_keypad, "0", true);
publishInt(mqtt_topic_query_keypad, 0, true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_BATTERY;
publishString(mqtt_topic_query_battery, "0", true);
publishInt(mqtt_topic_query_battery, 0, true);
}
if(comparePrefixedPath(topic, mqtt_topic_config_action))
@@ -1053,6 +1036,7 @@ void NukiNetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entr
char uidString[20];
itoa(_preferences->getUInt(preference_nuki_id_lock, 0), uidString, 16);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/lock");
JsonDocument json;
for(const auto& entry : entries)
@@ -1296,6 +1280,7 @@ void NukiNetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEn
char uidString[20];
itoa(_preferences->getUInt(preference_nuki_id_lock, 0), uidString, 16);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/lock");
JsonDocument json;
for(const auto& entry : timeControlEntries)
@@ -1428,6 +1413,7 @@ void NukiNetworkLock::publishAuth(const std::list<NukiLock::AuthorizationEntry>&
char uidString[20];
itoa(_preferences->getUInt(preference_nuki_id_lock, 0), uidString, 16);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/lock");
JsonDocument json;
for(const auto& entry : authEntries)
@@ -1680,7 +1666,9 @@ bool NukiNetworkLock::comparePrefixedPath(const char *fullPath, const char *subP
void NukiNetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, char *name, char *uidString, const char *softwareVersion, const char *hardwareVersion, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char *lockAction,
char *unlockAction, char *openAction)
{
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, softwareVersion, hardwareVersion, "~/maintenance/mqttConnectionState", hasKeypad, lockAction, unlockAction, openAction);
String availabilityTopic = _preferences->getString(preference_mqtt_lock_path);
availabilityTopic.concat("/maintenance/mqttConnectionState");
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, softwareVersion, hardwareVersion, availabilityTopic.c_str(), hasKeypad, lockAction, unlockAction, openAction);
_network->publishHASSConfigAdditionalLockEntities(deviceType, baseTopic, name, uidString);
if(hasDoorSensor)
@@ -1719,57 +1707,63 @@ void NukiNetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic,
void NukiNetworkLock::removeHASSConfig(char *uidString)
{
return _network->removeHASSConfig(uidString);
_network->removeHASSConfig(uidString);
}
void NukiNetworkLock::publishOffAction(const int value)
{
return _network->publishInt(_nukiOfficial->getMqttPath(), mqtt_topic_official_lock_action, value, false);
_network->publishInt(_nukiOfficial->getMqttPath(), mqtt_topic_official_lock_action, value, false);
}
void NukiNetworkLock::publishFloat(const char *topic, const float value, bool retain, const uint8_t precision)
{
return _nukiPublisher->publishFloat(topic, value, retain, precision);
_nukiPublisher->publishFloat(topic, value, retain, precision);
}
void NukiNetworkLock::publishInt(const char *topic, const int value, bool retain)
{
return _nukiPublisher->publishInt(topic, value, retain);
_nukiPublisher->publishInt(topic, value, retain);
}
void NukiNetworkLock::publishUInt(const char *topic, const unsigned int value, bool retain)
{
return _nukiPublisher->publishUInt(topic, value, retain);
_nukiPublisher->publishUInt(topic, value, retain);
}
void NukiNetworkLock::publishBool(const char *topic, const bool value, bool retain)
{
return _nukiPublisher->publishBool(topic, value, retain);
_nukiPublisher->publishBool(topic, value, retain);
}
bool NukiNetworkLock::publishString(const char *topic, const String &value, bool retain)
void NukiNetworkLock::publishString(const char *topic, const String &value, bool retain)
{
return _nukiPublisher->publishString(topic, value, retain);
char str[value.length() + 1];
memset(str, 0, sizeof(str));
memcpy(str, value.begin(), value.length());
publishString(topic, str, retain);
}
bool NukiNetworkLock::publishString(const char *topic, const std::string &value, bool retain)
void NukiNetworkLock::publishString(const char *topic, const std::string &value, bool retain)
{
return _nukiPublisher->publishString(topic, value, retain);
char str[value.size() + 1];
memset(str, 0, sizeof(str));
memcpy(str, value.data(), value.length());
publishString(topic, str, retain);
}
bool NukiNetworkLock::publishString(const char *topic, const char *value, bool retain)
void NukiNetworkLock::publishString(const char *topic, const char *value, bool retain)
{
return _nukiPublisher->publishString(topic, value, retain);
_nukiPublisher->publishString(topic, value, retain);
}
void NukiNetworkLock::publishULong(const char *topic, const unsigned long value, bool retain)
{
return _nukiPublisher->publishULong(topic, value, retain);
_nukiPublisher->publishULong(topic, value, retain);
}
void NukiNetworkLock::publishLongLong(const char *topic, int64_t value, bool retain)
{
return _nukiPublisher->publishLongLong(topic, value, retain);
_nukiPublisher->publishLongLong(topic, value, retain);
}
String NukiNetworkLock::concat(String a, String b)
@@ -1786,6 +1780,11 @@ bool NukiNetworkLock::reconnected()
return r;
}
int NukiNetworkLock::mqttConnectionState()
{
return _network->mqttConnectionState();
}
uint8_t NukiNetworkLock::queryCommands()
{
uint8_t qc = _queryCommands;

View File

@@ -57,7 +57,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(char* topic, int topic_len, char* data, int data_len) override;
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) 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);
@@ -65,12 +65,12 @@ public:
void publishULong(const char* topic, const unsigned long value, bool retain);
void publishLongLong(const char* topic, int64_t value, bool retain);
void publishBool(const char* topic, const bool value, bool retain);
bool publishString(const char* topic, const String& value, bool retain);
bool publishString(const char* topic, const std::string& value, bool retain);
bool publishString(const char* topic, const char* value, bool retain);
void publishString(const char* topic, const String& value, bool retain);
void publishString(const char* topic, const std::string& value, bool retain);
void publishString(const char* topic, const char* value, bool retain);
const uint32_t getAuthId() const;
int mqttConnectionState();
bool reconnected();
uint8_t queryCommands();
@@ -99,7 +99,7 @@ private:
bool _firstTunerStatePublish = true;
int64_t _lastMaintenanceTs = 0;
bool _haEnabled = false;
bool _reconnected = false;
bool _reconnected = false; //SETBACK
bool _disableNonJSON = false;
String _keypadCommandName = "";

View File

@@ -22,24 +22,18 @@ NukiNetworkOpener::NukiNetworkOpener(NukiNetwork* network, Preferences* preferen
void NukiNetworkOpener::initialize()
{
String mqttPath = _preferences->getString(preference_mqtt_opener_path);
if(mqttPath.length() > 0)
String mqttPath = _preferences->getString(preference_mqtt_lock_path, "");
mqttPath.concat("/opener");
size_t len = mqttPath.length();
for(int i=0; i < len; i++)
{
size_t len = mqttPath.length();
for(int i=0; i < len; i++)
{
_mqttPath[i] = mqttPath.charAt(i);
}
}
else
{
strcpy(_mqttPath, "nukiopener");
_preferences->putString(preference_mqtt_opener_path, _mqttPath);
_mqttPath[i] = mqttPath.charAt(i);
}
_haEnabled = _preferences->getString(preference_mqtt_hass_discovery, "") != "";
_disableNonJSON = _preferences->getBool(preference_disable_non_json, false);
_network->initTopic(_mqttPath, mqtt_topic_lock_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_lock_action);
_network->initTopic(_mqttPath, mqtt_topic_config_action, "--");
@@ -52,7 +46,7 @@ void NukiNetworkOpener::initialize()
_network->subscribe(_mqttPath, mqtt_topic_query_config);
_network->subscribe(_mqttPath, mqtt_topic_query_lockstate);
_network->subscribe(_mqttPath, mqtt_topic_query_battery);
if(_disableNonJSON)
{
_network->removeTopic(_mqttPath, mqtt_topic_keypad_command_action);
@@ -69,7 +63,6 @@ void NukiNetworkOpener::initialize()
_network->removeTopic(_mqttPath, mqtt_topic_battery_charging);
_network->removeTopic(_mqttPath, mqtt_topic_battery_voltage);
_network->removeTopic(_mqttPath, mqtt_topic_battery_keypad_critical);
//_network->removeTopic(_mqttPath, mqtt_topic_presence);
}
if(!_preferences->getBool(preference_conf_info_enabled, true))
@@ -88,34 +81,34 @@ void NukiNetworkOpener::initialize()
{
if(!_disableNonJSON)
{
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_action, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_id, "0");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_name, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_code, "000000");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_enabled, "1");
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_action);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_id);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_name);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_code);
_network->subscribe(_mqttPath, mqtt_topic_keypad_command_enabled);
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_action, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_id, "0");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_name, "--");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_code, "000000");
_network->initTopic(_mqttPath, mqtt_topic_keypad_command_enabled, "1");
}
_network->subscribe(_mqttPath, mqtt_topic_query_keypad);
_network->subscribe(_mqttPath, mqtt_topic_keypad_json_action);
_network->initTopic(_mqttPath, mqtt_topic_query_keypad, "0");
_network->initTopic(_mqttPath, mqtt_topic_keypad_json_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_query_keypad);
_network->subscribe(_mqttPath, mqtt_topic_keypad_json_action);
}
if(_preferences->getBool(preference_timecontrol_control_enabled, false))
{
_network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_timecontrol_action);
}
if(_preferences->getBool(preference_auth_control_enabled))
{
_network->subscribe(_mqttPath, mqtt_topic_auth_action);
_network->initTopic(_mqttPath, mqtt_topic_auth_action, "--");
_network->subscribe(_mqttPath, mqtt_topic_auth_action);
}
if(_preferences->getBool(preference_publish_authdata, false))
@@ -124,9 +117,9 @@ void NukiNetworkOpener::initialize()
}
_network->addReconnectedCallback([&]()
{
_reconnected = true;
});
{
_reconnected = true;
});
}
void NukiNetworkOpener::update()
@@ -138,8 +131,10 @@ void NukiNetworkOpener::update()
}
}
void NukiNetworkOpener::onMqttDataReceived(char* topic, int topic_len, char* data, int data_len)
void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
{
char* data = (char*)payload;
if(_network->mqttRecentlyConnected() && _network->pathEquals(_mqttPath, mqtt_topic_lock_action, topic))
{
Log->println("MQTT recently connected, ignoring opener action.");
@@ -246,22 +241,22 @@ void NukiNetworkOpener::onMqttDataReceived(char* topic, int topic_len, char* dat
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_CONFIG;
publishString(mqtt_topic_query_config, "0", true);
publishInt(mqtt_topic_query_config, 0, true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_LOCKSTATE;
publishString(mqtt_topic_query_lockstate, "0", true);
publishInt(mqtt_topic_query_lockstate, 0, true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_KEYPAD;
publishString(mqtt_topic_query_keypad, "0", true);
publishInt(mqtt_topic_query_keypad, 0, true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(data, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_BATTERY;
publishString(mqtt_topic_query_battery, "0", true);
publishInt(mqtt_topic_query_battery, 0, true);
}
if(comparePrefixedPath(topic, mqtt_topic_config_action))
@@ -849,7 +844,7 @@ void NukiNetworkOpener::publishBleAddress(const std::string &address)
void NukiNetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const bool& publishAuthData, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction)
{
String availabilityTopic = _preferences->getString("mqttpath");
String availabilityTopic = _preferences->getString(preference_mqtt_lock_path);
availabilityTopic.concat("/maintenance/mqttConnectionState");
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, softwareVersion, hardwareVersion, availabilityTopic.c_str(), hasKeypad, lockAction, unlockAction, openAction);
@@ -886,7 +881,8 @@ void NukiNetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& en
uint index = 0;
char uidString[20];
itoa(_preferences->getUInt(preference_nuki_id_opener, 0), uidString, 16);
String baseTopic = _preferences->getString(preference_mqtt_opener_path);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/opener");
JsonDocument json;
for(const auto& entry : entries)
@@ -1098,7 +1094,8 @@ void NukiNetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeContr
char str[50];
char uidString[20];
itoa(_preferences->getUInt(preference_nuki_id_opener, 0), uidString, 16);
String baseTopic = _preferences->getString(preference_mqtt_opener_path);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/opener");
JsonDocument json;
for(const auto& entry : timeControlEntries)
@@ -1228,7 +1225,8 @@ void NukiNetworkOpener::publishAuth(const std::list<NukiOpener::AuthorizationEnt
char str[50];
char uidString[20];
itoa(_preferences->getUInt(preference_nuki_id_opener, 0), uidString, 16);
String baseTopic = _preferences->getString(preference_mqtt_opener_path);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/opener");
JsonDocument json;
for(const auto& entry : authEntries)
@@ -1561,6 +1559,11 @@ bool NukiNetworkOpener::reconnected()
return r;
}
int NukiNetworkOpener::mqttConnectionState()
{
return _network->mqttConnectionState();
}
uint8_t NukiNetworkOpener::queryCommands()
{
uint8_t qc = _queryCommands;

View File

@@ -48,9 +48,10 @@ public:
void setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char* value));
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
void setAuthCommandReceivedCallback(void (*authCommandReceivedReceivedCallback)(const char* value));
void onMqttDataReceived(char* topic, int topic_len, char* data, int data_len) override;
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
bool reconnected();
int mqttConnectionState();
bool reconnected(); //SETBACK
uint8_t queryCommands();
char _nukiName[33];
@@ -87,7 +88,7 @@ private:
bool _isConnected = false;
bool _firstTunerStatePublish = true;
bool _haEnabled = false;
bool _reconnected = false;
bool _reconnected = false; //SETBACK
bool _disableNonJSON = false;
String _keypadCommandName = "";

View File

@@ -69,7 +69,7 @@ private:
uint8_t offTrigger = 0;
uint32_t offAuthId = 0;
uint32_t offCodeId = 0;
// uint8_t offContext = 0;
//uint8_t offContext = 0;
bool offEnabled = false;
};

View File

@@ -114,6 +114,8 @@ void NukiOpenerWrapper::readSettings()
_rssiPublishInterval = _preferences->getInt(preference_rssi_publish_interval) * 1000;
_disableNonJSON = _preferences->getBool(preference_disable_non_json, false);
_checkKeypadCodes = _preferences->getBool(preference_keypad_check_code_enabled, false);
_pairedAsApp = _preferences->getBool(preference_register_opener_as_app, false);
_preferences->getBytes(preference_conf_opener_basic_acl, &_basicOpenerConfigAclPrefs, sizeof(_basicOpenerConfigAclPrefs));
_preferences->getBytes(preference_conf_opener_advanced_acl, &_advancedOpenerConfigAclPrefs, sizeof(_advancedOpenerConfigAclPrefs));
@@ -216,67 +218,65 @@ void NukiOpenerWrapper::update()
_nukiOpener.updateConnectionState();
if(_statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
if(_network->mqttConnectionState() == 2)
{
_statusUpdated = false;
_nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
updateKeyTurnerState();
_network->publishStatusUpdated(_statusUpdated);
}
if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0)
{
_nextBatteryReportTs = ts + _intervalBattery * 1000;
updateBatteryState();
}
if(_nextConfigUpdateTs == 0 || ts > _nextConfigUpdateTs || (queryCommands & QUERY_COMMAND_CONFIG) > 0)
{
_nextConfigUpdateTs = ts + _intervalConfig * 1000;
updateConfig();
if(_hassEnabled && !_hassSetupCompleted)
if(_statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
{
_statusUpdated = false;
_nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
updateKeyTurnerState();
_network->publishStatusUpdated(_statusUpdated);
}
if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0)
{
_nextBatteryReportTs = ts + _intervalBattery * 1000;
updateBatteryState();
}
if(_nextConfigUpdateTs == 0 || ts > _nextConfigUpdateTs || (queryCommands & QUERY_COMMAND_CONFIG) > 0)
{
_nextConfigUpdateTs = ts + _intervalConfig * 1000;
updateConfig();
}
if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs)
{
_waitAuthLogUpdateTs = 0;
updateAuthData(true);
}
if(_waitKeypadUpdateTs != 0 && ts > _waitKeypadUpdateTs)
{
_waitKeypadUpdateTs = 0;
updateKeypad(true);
}
if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs)
{
_waitTimeControlUpdateTs = 0;
updateTimeControl(true);
}
if(_waitAuthUpdateTs != 0 && ts > _waitAuthUpdateTs)
{
_waitAuthUpdateTs = 0;
updateAuth(true);
}
if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && !_hassSetupCompleted)
{
setupHASS();
}
}
if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs)
{
_waitAuthLogUpdateTs = 0;
updateAuthData(true);
}
if(_waitKeypadUpdateTs != 0 && ts > _waitKeypadUpdateTs)
{
_waitKeypadUpdateTs = 0;
updateKeypad(true);
}
if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs)
{
_waitTimeControlUpdateTs = 0;
updateTimeControl(true);
}
if(_waitAuthUpdateTs != 0 && ts > _waitAuthUpdateTs)
{
_waitAuthUpdateTs = 0;
updateAuth(true);
}
if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && _network->reconnected())
{
setupHASS();
}
if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
{
_nextRssiTs = ts + _rssiPublishInterval;
int rssi = _nukiOpener.getRssi();
if(rssi != _lastRssi)
if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
{
_network->publishRssi(rssi);
_lastRssi = rssi;
}
}
_nextRssiTs = ts + _rssiPublishInterval;
if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0))
{
_nextKeypadUpdateTs = ts + _intervalKeypad * 1000;
updateKeypad(false);
int rssi = _nukiOpener.getRssi();
if(rssi != _lastRssi)
{
_network->publishRssi(rssi);
_lastRssi = rssi;
}
}
if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0))
{
_nextKeypadUpdateTs = ts + _intervalKeypad * 1000;
updateKeypad(false);
}
}
if(_checkKeypadCodes && _invalidCount > 0 && ts - 120000 < _lastCodeCheck)
@@ -540,7 +540,7 @@ void NukiOpenerWrapper::updateConfig()
if(_preferences->getUInt(preference_nuki_id_opener, 0) == _nukiConfig.nukiId)
{
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2 > 0;
_hasKeypad = _nukiConfig.hasKeypad == 1 || _nukiConfig.hasKeypadV2 == 1;
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
if(_preferences->getBool(preference_conf_info_enabled, true))
@@ -889,6 +889,12 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
void NukiOpenerWrapper::updateAuth(bool retrieved)
{
if(!isPinValid())
{
Log->println(F("No valid Nuki Lock PIN set"));
return;
}
if(!_preferences->getBool(preference_auth_info_enabled))
{
return;
@@ -3870,7 +3876,7 @@ BleScanner::Scanner *NukiOpenerWrapper::bleScanner()
void NukiOpenerWrapper::notify(Nuki::EventType eventType)
{
if(eventType == Nuki::EventType::KeyTurnerStatusUpdated)
if(!_pairedAsApp && eventType == Nuki::EventType::KeyTurnerStatusUpdated && !_statusUpdated)
{
Log->println("KeyTurnerStatusUpdated");
_statusUpdated = true;
@@ -3946,7 +3952,8 @@ void NukiOpenerWrapper::setupHASS()
return;
}
String baseTopic = _preferences->getString(preference_mqtt_opener_path);
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/opener");
char uidString[20];
itoa(_nukiConfig.nukiId, uidString, 16);

View File

@@ -107,6 +107,7 @@ private:
bool _clearAuthData = false;
bool _disableNonJSON = false;
bool _checkKeypadCodes = false;
bool _pairedAsApp = false;
int _nrOfRetries = 0;
int _retryDelay = 0;
int _retryConfigCount = 0;

View File

@@ -27,33 +27,27 @@ void NukiPublisher::publishBool(const char *topic, const bool value, bool retain
_network->publishBool(_mqttPath, topic, value, retain);
}
bool NukiPublisher::publishString(const char *topic, const String &value, bool retain)
void NukiPublisher::publishString(const char *topic, const String &value, bool retain)
{
char str[value.length() + 1];
memset(str, 0, sizeof(str));
memcpy(str, value.begin(), value.length());
return publishString(topic, str, retain);
publishString(topic, value.c_str(), retain);
}
bool NukiPublisher::publishString(const char *topic, const std::string &value, bool retain)
void NukiPublisher::publishString(const char *topic, const std::string &value, bool retain)
{
char str[value.size() + 1];
memset(str, 0, sizeof(str));
memcpy(str, value.data(), value.length());
return publishString(topic, str, retain);
publishString(topic, value.c_str(), retain);
}
bool NukiPublisher::publishString(const char *topic, const char *value, bool retain)
void NukiPublisher::publishString(const char *topic, const char *value, bool retain)
{
return _network->publishString(_mqttPath, topic, value, retain);
_network->publishString(_mqttPath, topic, value, retain);
}
void NukiPublisher::publishULong(const char *topic, const unsigned long value, bool retain)
{
return _network->publishULong(_mqttPath, topic, value, retain);
_network->publishULong(_mqttPath, topic, value, retain);
}
void NukiPublisher::publishLongLong(const char *topic, int64_t value, bool retain)
{
return _network->publishLongLong(_mqttPath, topic, value, retain);
_network->publishLongLong(_mqttPath, topic, value, retain);
}

View File

@@ -14,9 +14,9 @@ public:
void publishULong(const char* topic, const unsigned long value, bool retain);
void publishLongLong(const char* topic, int64_t value, bool retain);
void publishBool(const char* topic, const bool value, bool retain);
bool publishString(const char* topic, const String& value, bool retain);
bool publishString(const char* topic, const std::string& value, bool retain);
bool publishString(const char* topic, const char* value, bool retain);
void publishString(const char* topic, const String& value, bool retain);
void publishString(const char* topic, const std::string& value, bool retain);
void publishString(const char* topic, const char* value, bool retain);
private:
NukiNetwork* _network;

View File

@@ -82,6 +82,8 @@ void NukiWrapper::initialize(const bool& firstStart)
Log->println("Failed to clear NVS Wi-Fi configuration");
}
#endif
_preferences->putString(preference_mqtt_lock_path, "nukihub");
_preferences->putBool(preference_check_updates, true);
_preferences->putBool(preference_opener_continuous_mode, false);
_preferences->putBool(preference_official_hybrid_enabled, false);
@@ -184,6 +186,8 @@ void NukiWrapper::readSettings()
_rssiPublishInterval = _preferences->getInt(preference_rssi_publish_interval) * 1000;
_disableNonJSON = _preferences->getBool(preference_disable_non_json, false);
_checkKeypadCodes = _preferences->getBool(preference_keypad_check_code_enabled, false);
_pairedAsApp = _preferences->getBool(preference_register_as_app, false);
_preferences->getBytes(preference_conf_lock_basic_acl, &_basicLockConfigaclPrefs, sizeof(_basicLockConfigaclPrefs));
_preferences->getBytes(preference_conf_lock_advanced_acl, &_advancedLockConfigaclPrefs, sizeof(_advancedLockConfigaclPrefs));
@@ -355,84 +359,83 @@ void NukiWrapper::update()
_nextLockAction = (NukiLock::LockAction) 0xff;
}
}
if(_nukiOfficial->getStatusUpdated() || _statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
if(_network->mqttConnectionState() == 2)
{
Log->println("Updating Lock state based on status, timer or query");
_statusUpdated = false;
_nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
updateKeyTurnerState();
_network->publishStatusUpdated(_statusUpdated);
}
if(!_statusUpdated)
{
if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0)
if(_nukiOfficial->getStatusUpdated() || _statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
{
Log->println("Updating Lock battery state based on timer or query");
_nextBatteryReportTs = ts + _intervalBattery * 1000;
updateBatteryState();
Log->println("Updating Lock state based on status, timer or query");
_statusUpdated = false;
_nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
updateKeyTurnerState();
_network->publishStatusUpdated(_statusUpdated);
}
if(_nextConfigUpdateTs == 0 || ts > _nextConfigUpdateTs || (queryCommands & QUERY_COMMAND_CONFIG) > 0)
if(!_statusUpdated)
{
Log->println("Updating Lock config based on timer or query");
_nextConfigUpdateTs = ts + _intervalConfig * 1000;
updateConfig();
if(_hassEnabled && !_hassSetupCompleted)
if(_nextBatteryReportTs == 0 || ts > _nextBatteryReportTs || (queryCommands & QUERY_COMMAND_BATTERY) > 0)
{
Log->println("Updating Lock battery state based on timer or query");
_nextBatteryReportTs = ts + _intervalBattery * 1000;
updateBatteryState();
}
if(_nextConfigUpdateTs == 0 || ts > _nextConfigUpdateTs || (queryCommands & QUERY_COMMAND_CONFIG) > 0)
{
Log->println("Updating Lock config based on timer or query");
_nextConfigUpdateTs = ts + _intervalConfig * 1000;
updateConfig();
}
if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs)
{
_waitAuthLogUpdateTs = 0;
updateAuthData(true);
}
if(_waitKeypadUpdateTs != 0 && ts > _waitKeypadUpdateTs)
{
_waitKeypadUpdateTs = 0;
updateKeypad(true);
}
if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs)
{
_waitTimeControlUpdateTs = 0;
updateTimeControl(true);
}
if(_waitAuthUpdateTs != 0 && ts > _waitAuthUpdateTs)
{
_waitAuthUpdateTs = 0;
updateAuth(true);
}
if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && !_hassSetupCompleted)
{
setupHASS();
}
}
if(_waitAuthLogUpdateTs != 0 && ts > _waitAuthLogUpdateTs)
{
_waitAuthLogUpdateTs = 0;
updateAuthData(true);
}
if(_waitKeypadUpdateTs != 0 && ts > _waitKeypadUpdateTs)
{
_waitKeypadUpdateTs = 0;
updateKeypad(true);
}
if(_waitTimeControlUpdateTs != 0 && ts > _waitTimeControlUpdateTs)
{
_waitTimeControlUpdateTs = 0;
updateTimeControl(true);
}
if(_waitAuthUpdateTs != 0 && ts > _waitAuthUpdateTs)
{
_waitAuthUpdateTs = 0;
updateAuth(true);
}
if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && _network->reconnected())
{
setupHASS();
}
if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
{
_nextRssiTs = ts + _rssiPublishInterval;
int rssi = _nukiLock.getRssi();
if(rssi != _lastRssi)
if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
{
_network->publishRssi(rssi);
_lastRssi = rssi;
_nextRssiTs = ts + _rssiPublishInterval;
int rssi = _nukiLock.getRssi();
if(rssi != _lastRssi)
{
_network->publishRssi(rssi);
_lastRssi = rssi;
}
}
if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0))
{
Log->println("Updating Lock keypad based on timer or query");
_nextKeypadUpdateTs = ts + _intervalKeypad * 1000;
updateKeypad(false);
}
}
if(_hasKeypad && _keypadEnabled && (_nextKeypadUpdateTs == 0 || ts > _nextKeypadUpdateTs || (queryCommands & QUERY_COMMAND_KEYPAD) > 0))
if(_clearAuthData)
{
Log->println("Updating Lock keypad based on timer or query");
_nextKeypadUpdateTs = ts + _intervalKeypad * 1000;
updateKeypad(false);
Log->println("Clearing Lock auth data");
_network->clearAuthorizationInfo();
_clearAuthData = false;
}
if(_checkKeypadCodes && _invalidCount > 0 && ts - 120000 < _lastCodeCheck)
{
_invalidCount--;
}
}
if(_clearAuthData)
{
Log->println("Clearing Lock auth data");
_network->clearAuthorizationInfo();
_clearAuthData = false;
}
memcpy(&_lastKeyTurnerState, &_keyTurnerState, sizeof(NukiLock::KeyTurnerState));
}
@@ -625,7 +628,7 @@ void NukiWrapper::updateConfig()
if(_preferences->getUInt(preference_nuki_id_lock, 0) == _nukiConfig.nukiId)
{
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2 > 0;
_hasKeypad = _nukiConfig.hasKeypad == 1 || _nukiConfig.hasKeypadV2 == 1;
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
if(_preferences->getBool(preference_conf_info_enabled, true))
@@ -968,6 +971,12 @@ void NukiWrapper::updateTimeControl(bool retrieved)
void NukiWrapper::updateAuth(bool retrieved)
{
if(!isPinValid())
{
Log->println(F("No valid Nuki Lock PIN set"));
return;
}
if(!_preferences->getBool(preference_auth_info_enabled))
{
return;
@@ -3985,7 +3994,7 @@ void NukiWrapper::notify(Nuki::EventType eventType)
}
else
{
if(eventType == Nuki::EventType::KeyTurnerStatusUpdated)
if(!_pairedAsApp && eventType == Nuki::EventType::KeyTurnerStatusUpdated && !_statusUpdated)
{
Log->println("KeyTurnerStatusUpdated");
_statusUpdated = true;
@@ -4064,6 +4073,7 @@ void NukiWrapper::setupHASS()
}
String baseTopic = _preferences->getString(preference_mqtt_lock_path);
baseTopic.concat("/lock");
char uidString[20];
itoa(_nukiConfig.nukiId, uidString, 16);

View File

@@ -131,6 +131,7 @@ private:
bool _hassEnabled = false;
bool _hassSetupCompleted = false;
bool _disableNonJSON = false;
bool _pairedAsApp = false;
bool _paired = false;
bool _statusUpdated = false;
bool _hasKeypad = false;

View File

@@ -18,7 +18,6 @@
#define preference_lock_enabled (char*)"lockena"
#define preference_mqtt_lock_path (char*)"mqttpath"
#define preference_opener_enabled (char*)"openerena"
#define preference_mqtt_opener_path (char*)"mqttoppath"
#define preference_mqtt_ca (char*)"mqttca"
#define preference_mqtt_crt (char*)"mqttcrt"
#define preference_mqtt_key (char*)"mqttkey"
@@ -54,6 +53,7 @@
#define preference_official_hybrid_enabled (char*)"offHybrid"
#define preference_wifi_ssid (char*)"wifiSSID"
#define preference_wifi_pass (char*)"wifiPass"
#define preference_disable_network_not_connected (char*)"disNtwNoCon"
// CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT
#define preference_ntw_reconfigure (char*)"ntwRECONF"
@@ -276,7 +276,7 @@ private:
preference_started_before, preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener,
preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates,
preference_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status,
preference_opener_continuous_mode, preference_mqtt_opener_path, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count,
preference_opener_continuous_mode, 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,
@@ -292,7 +292,8 @@ private:
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_keypad_check_code_enabled, preference_wifi_ssid, preference_wifi_pass
preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries, preference_wifi_ssid, preference_wifi_pass,
preference_keypad_check_code_enabled, preference_disable_network_not_connected
};
std::vector<char*> _redact =
{
@@ -308,7 +309,7 @@ private:
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_webserial_enabled,
preference_ntw_reconfigure, preference_keypad_check_code_enabled
preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected
};
std::vector<char*> _bytePrefs =
{

View File

@@ -25,6 +25,7 @@ enum class RestartReason
DeviceUnpaired,
NukiHubReset,
ReconfigureWebServer,
DisableNetworkIfNotConnected,
NotApplicable
};
@@ -112,6 +113,8 @@ inline static String getRestartReason()
return "DeviceUnpaired";
case RestartReason::NukiHubReset:
return "NukiHubFactoryReset";
case RestartReason::DisableNetworkIfNotConnected:
return "NetworkDisabledOnNotConnected";
case RestartReason::NotApplicable:
return "NotApplicable";
default:

View File

@@ -245,6 +245,14 @@ void WebCfgServer::initialize()
}
return buildCredHtml(request);
});
_psychicServer->on("/ntwconfig", HTTP_GET, [&](PsychicRequest *request)
{
if(strlen(_credUser) > 0 && strlen(_credPassword) > 0) if(!request->authenticate(_credUser, _credPassword))
{
return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in.");
}
return buildNetworkConfigHtml(request);
});
_psychicServer->on("/mqttconfig", HTTP_GET, [&](PsychicRequest *request)
{
if(strlen(_credUser) > 0 && strlen(_credPassword) > 0) if(!request->authenticate(_credUser, _credPassword))
@@ -1518,16 +1526,6 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message)
configChanged = true;
}
}
else if(key == "MQTTOPPATH")
{
if(_preferences->getString(preference_mqtt_opener_path, "") != value)
{
_preferences->putString(preference_mqtt_opener_path, value);
Log->print(F("Setting changed: "));
Log->println(key);
configChanged = true;
}
}
else if(key == "MQTTCA")
{
if(_preferences->getString(preference_mqtt_ca, "") != value)
@@ -2128,6 +2126,16 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message)
//configChanged = true;
}
}
else if(key == "DISNTWNOCON")
{
if(_preferences->getBool(preference_disable_network_not_connected, false) != (value == "1"))
{
_preferences->putBool(preference_disable_network_not_connected, (value == "1"));
Log->print(F("Setting changed: "));
Log->println(key);
configChanged = true;
}
}
else if(key == "OTAUPD")
{
if(_preferences->getString(preference_ota_updater_url, "") != value)
@@ -3344,7 +3352,8 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request)
}
response.print("</table><br>");
response.print("<ul id=\"tblnav\">");
buildNavigationMenuEntry(&response, "MQTT and Network Configuration", "/mqttconfig", _brokerConfigured ? "" : "Please configure MQTT broker");
buildNavigationMenuEntry(&response, "Network Configuration", "/ntwconfig");
buildNavigationMenuEntry(&response, "MQTT Configuration", "/mqttconfig", _brokerConfigured ? "" : "Please configure MQTT broker");
buildNavigationMenuEntry(&response, "Nuki Configuration", "/nukicfg");
buildNavigationMenuEntry(&response, "Access Level Configuration", "/acclvl");
buildNavigationMenuEntry(&response, "Credentials", "/cred", _pinsConfigured ? "" : "Please configure PIN");
@@ -3454,48 +3463,23 @@ esp_err_t WebCfgServer::buildCredHtml(PsychicRequest *request)
return response.endSend();
}
esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request)
esp_err_t WebCfgServer::buildNetworkConfigHtml(PsychicRequest *request)
{
PsychicStreamResponse response(request, "text/plain");
response.beginSend();
buildHtmlHeader(&response);
response.print("<form class=\"adapt\" method=\"post\" action=\"savecfg\">");
response.print("<h3>Basic MQTT and Network Configuration</h3>");
response.print("<h3>Network Configuration</h3>");
response.print("<table>");
printInputField(&response, "HOSTNAME", "Host name", _preferences->getString(preference_hostname).c_str(), 100, "");
printInputField(&response, "MQTTSERVER", "MQTT Broker", _preferences->getString(preference_mqtt_broker).c_str(), 100, "");
printInputField(&response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5, "");
printInputField(&response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30, "", false, true);
printInputField(&response, "MQTTPASS", "MQTT Password", "*", 30, "", true, true);
response.print("</table><br>");
response.print("<h3>Advanced MQTT and Network Configuration</h3>");
response.print("<table>");
printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, "");
printInputField(&response, "HASSCUURL", "Home Assistant device configuration URL (empty to use http://LOCALIP; fill when using a reverse proxy for example)", _preferences->getString(preference_mqtt_hass_cu_url).c_str(), 261, "");
if(_preferences->getBool(preference_opener_enabled, false))
{
printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), "");
}
printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, true, true);
printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, true, true);
printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, true, true);
printDropDown(&response, "NWHW", "Network hardware", String(_preferences->getInt(preference_network_hardware)), getNetworkDetectionOptions(), "");
printInputField(&response, "HASSCUURL", "Home Assistant device configuration URL (empty to use http://LOCALIP; fill when using a reverse proxy for example)", _preferences->getString(preference_mqtt_hass_cu_url).c_str(), 261, "");
#ifndef CONFIG_IDF_TARGET_ESP32H2
printInputField(&response, "RSSI", "RSSI Publish interval (seconds; -1 to disable)", _preferences->getInt(preference_rssi_publish_interval), 6, "");
#endif
printInputField(&response, "NETTIMEOUT", "MQTT Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5, "");
printCheckBox(&response, "RSTDISC", "Restart on disconnect", _preferences->getBool(preference_restart_on_disconnect), "");
printCheckBox(&response, "MQTTLOG", "Enable MQTT logging", _preferences->getBool(preference_mqtt_log_enabled), "");
printCheckBox(&response, "CHECKUPDATE", "Check for Firmware Updates every 24h", _preferences->getBool(preference_check_updates), "");
printCheckBox(&response, "UPDATEMQTT", "Allow updating using MQTT", _preferences->getBool(preference_update_from_mqtt), "");
printCheckBox(&response, "DISNONJSON", "Disable some extraneous non-JSON topics", _preferences->getBool(preference_disable_non_json), "");
printCheckBox(&response, "OFFHYBRID", "Enable hybrid official MQTT and Nuki Hub setup", _preferences->getBool(preference_official_hybrid_enabled), "");
printCheckBox(&response, "HYBRIDACT", "Enable sending actions through official MQTT", _preferences->getBool(preference_official_hybrid_actions), "");
printInputField(&response, "HYBRIDTIMER", "Time between status updates when official MQTT is offline (seconds)", _preferences->getInt(preference_query_interval_hybrid_lockstate), 5, "");
// printCheckBox(&response, "HYBRIDRETRY", "Retry command sent using official MQTT over BLE if failed", _preferences->getBool(preference_official_hybrid_retry), ""); // NOT IMPLEMENTED (YET?)
response.print("</table>");
response.print("* If no encryption is configured for the MQTT broker, leave empty.<br><br>");
response.print("<h3>IP Address assignment</h3>");
response.print("<table>");
printCheckBox(&response, "DHCPENA", "Enable DHCP", _preferences->getBool(preference_ip_dhcp_enabled), "");
@@ -3510,6 +3494,47 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request)
return response.endSend();
}
esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request)
{
PsychicStreamResponse response(request, "text/plain");
response.beginSend();
buildHtmlHeader(&response);
response.print("<form class=\"adapt\" method=\"post\" action=\"savecfg\">");
response.print("<h3>Basic MQTT Configuration</h3>");
response.print("<table>");
printInputField(&response, "MQTTSERVER", "MQTT Broker", _preferences->getString(preference_mqtt_broker).c_str(), 100, "");
printInputField(&response, "MQTTPORT", "MQTT Broker port", _preferences->getInt(preference_mqtt_broker_port), 5, "");
printInputField(&response, "MQTTUSER", "MQTT User (# to clear)", _preferences->getString(preference_mqtt_user).c_str(), 30, "", false, true);
printInputField(&response, "MQTTPASS", "MQTT Password", "*", 30, "", true, true);
printInputField(&response, "MQTTPATH", "MQTT NukiHub Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180, "");
response.print("</table><br>");
response.print("<h3>Advanced MQTT Configuration</h3>");
response.print("<table>");
printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, "");
if(_preferences->getBool(preference_opener_enabled, false))
{
printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), "");
}
printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, true, true);
printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, true, true);
printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, true, true);
printInputField(&response, "NETTIMEOUT", "MQTT Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5, "");
printCheckBox(&response, "MQTTLOG", "Enable MQTT logging", _preferences->getBool(preference_mqtt_log_enabled), "");
printCheckBox(&response, "UPDATEMQTT", "Allow updating using MQTT", _preferences->getBool(preference_update_from_mqtt), "");
printCheckBox(&response, "DISNONJSON", "Disable some extraneous non-JSON topics", _preferences->getBool(preference_disable_non_json), "");
printCheckBox(&response, "OFFHYBRID", "Enable hybrid official MQTT and Nuki Hub setup", _preferences->getBool(preference_official_hybrid_enabled), "");
printCheckBox(&response, "HYBRIDACT", "Enable sending actions through official MQTT", _preferences->getBool(preference_official_hybrid_actions), "");
printInputField(&response, "HYBRIDTIMER", "Time between status updates when official MQTT is offline (seconds)", _preferences->getInt(preference_query_interval_hybrid_lockstate), 5, "");
// printCheckBox(&response, "HYBRIDRETRY", "Retry command sent using official MQTT over BLE if failed", _preferences->getBool(preference_official_hybrid_retry), ""); // NOT IMPLEMENTED (YET?)
response.print("</table>");
response.print("* If no encryption is configured for the MQTT broker, leave empty.<br><br>");
response.print("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
response.print("</form>");
response.print("</body></html>");
return response.endSend();
}
esp_err_t WebCfgServer::buildAdvancedConfigHtml(PsychicRequest *request)
{
PsychicStreamResponse response(request, "text/plain");
@@ -3522,6 +3547,7 @@ esp_err_t WebCfgServer::buildAdvancedConfigHtml(PsychicRequest *request)
response.print("<tr><td>Current bootloop prevention state</td><td>");
response.print(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled");
response.print("</td></tr>");
printCheckBox(&response, "DISNTWNOCON", "Disable Network if not connected within 60s", _preferences->getBool(preference_disable_network_not_connected, false), "");
printCheckBox(&response, "WEBLOG", "Enable WebSerial logging", _preferences->getBool(preference_webserial_enabled), "");
printCheckBox(&response, "BTLPRST", "Enable Bootloop prevention (Try to reset these settings to default on bootloop)", true, "");
printInputField(&response, "BUFFSIZE", "Char buffer size (min 4096, max 32768)", _preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE), 6, "");
@@ -3864,15 +3890,7 @@ esp_err_t WebCfgServer::buildNukiConfigHtml(PsychicRequest *request)
response.print("<h3>Basic Nuki Configuration</h3>");
response.print("<table>");
printCheckBox(&response, "LOCKENA", "Nuki Lock enabled", _preferences->getBool(preference_lock_enabled), "");
if(_preferences->getBool(preference_lock_enabled))
{
printInputField(&response, "MQTTPATH", "MQTT Nuki Lock Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180, "");
}
printCheckBox(&response, "OPENA", "Nuki Opener enabled", _preferences->getBool(preference_opener_enabled), "");
if(_preferences->getBool(preference_opener_enabled))
{
printInputField(&response, "MQTTOPPATH", "MQTT Nuki Opener Path", _preferences->getString(preference_mqtt_opener_path).c_str(), 180, "");
}
response.print("</table><br>");
response.print("<h3>Advanced Nuki Configuration</h3>");
response.print("<table>");
@@ -4137,16 +4155,8 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request)
response.print(_preferences->getString(preference_mqtt_user, "").length() > 0 ? "***" : "Not set");
response.print("\nMQTT password: ");
response.print(_preferences->getString(preference_mqtt_password, "").length() > 0 ? "***" : "Not set");
if(_preferences->getBool(preference_lock_enabled, true))
{
response.print("\nMQTT lock base topic: ");
response.print(_preferences->getString(preference_mqtt_lock_path, ""));
}
if(_preferences->getBool(preference_opener_enabled, false))
{
response.print("\nMQTT opener base topic: ");
response.print(_preferences->getString(preference_mqtt_lock_path, ""));
}
response.print("\nMQTT base topic: ");
response.print(_preferences->getString(preference_mqtt_lock_path, ""));
response.print("\nMQTT SSL CA: ");
response.print(_preferences->getString(preference_mqtt_ca, "").length() > 0 ? "***" : "Not set");
response.print("\nMQTT SSL CRT: ");
@@ -4430,7 +4440,7 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request)
response.print(_nukiOpener->isPaired() ? _nukiOpener->isPinValid() ? "Yes" : "No" : "-");
response.print("\nOpener has keypad: ");
response.print(_nukiOpener->hasKeypad() ? "Yes" : "No");
if(_nuki->hasKeypad())
if(_nukiOpener->hasKeypad())
{
response.print("\nKeypad highest entries count: ");
response.print(_preferences->getInt(preference_opener_max_keypad_code_count, 0));

View File

@@ -54,6 +54,7 @@ private:
esp_err_t buildAccLvlHtml(PsychicRequest *request);
esp_err_t buildCredHtml(PsychicRequest *request);
esp_err_t buildImportExportHtml(PsychicRequest *request);
esp_err_t buildNetworkConfigHtml(PsychicRequest *request);
esp_err_t buildMqttConfigHtml(PsychicRequest *request);
esp_err_t buildStatusHtml(PsychicRequest *request);
esp_err_t buildAdvancedConfigHtml(PsychicRequest *request);

View File

@@ -42,6 +42,7 @@ Gpio* gpio = nullptr;
bool lockEnabled = false;
bool openerEnabled = false;
bool wifiConnected = false;
TaskHandle_t nukiTaskHandle = nullptr;
@@ -64,12 +65,16 @@ NukiNetwork* network = nullptr;
WebCfgServer* webCfgServer = nullptr;
Preferences* preferences = nullptr;
RTC_NOINIT_ATTR int espRunning;
RTC_NOINIT_ATTR int restartReason;
RTC_NOINIT_ATTR uint64_t restartReasonValidDetect;
RTC_NOINIT_ATTR bool rebuildGpioRequested;
RTC_NOINIT_ATTR uint64_t bootloopValidDetect;
RTC_NOINIT_ATTR int8_t bootloopCounter;
RTC_NOINIT_ATTR bool forceEnableWebServer;
RTC_NOINIT_ATTR bool disableNetwork;
RTC_NOINIT_ATTR bool wifiFallback;
RTC_NOINIT_ATTR bool ethCriticalFailure;
bool restartReason_isValid;
RestartReason currentRestartReason = RestartReason::NotApplicable;
@@ -144,14 +149,9 @@ void networkTask(void *pvParameters)
}
}
bool connected = network->update();
#ifndef NUKI_HUB_UPDATER
if(connected && networkLock != nullptr)
{
networkLock->update();
}
network->update();
bool connected = network->isConnected();
#ifdef DEBUG_NUKIHUB
if(connected && reroute)
{
@@ -159,6 +159,15 @@ void networkTask(void *pvParameters)
setReroute();
}
#endif
#ifndef NUKI_HUB_UPDATER
wifiConnected = network->wifiConnected();
if(connected && lockEnabled)
{
networkLock->update();
}
if(connected && openerEnabled)
{
networkOpener->update();
@@ -172,7 +181,6 @@ void networkTask(void *pvParameters)
}
esp_task_wdt_reset();
delay(100);
}
}
@@ -184,37 +192,40 @@ void nukiTask(void *pvParameters)
while(true)
{
bleScanner->update();
delay(20);
bool needsPairing = (lockEnabled && !nuki->isPaired()) || (openerEnabled && !nukiOpener->isPaired());
if (needsPairing)
if(disableNetwork || wifiConnected)
{
delay(5000);
}
else if (!whiteListed)
{
whiteListed = true;
bleScanner->update();
delay(20);
bool needsPairing = (lockEnabled && !nuki->isPaired()) || (openerEnabled && !nukiOpener->isPaired());
if (needsPairing)
{
delay(5000);
}
else if (!whiteListed)
{
whiteListed = true;
if(lockEnabled)
{
bleScanner->whitelist(nuki->getBleAddress());
}
if(openerEnabled)
{
bleScanner->whitelist(nukiOpener->getBleAddress());
}
}
if(lockEnabled)
{
bleScanner->whitelist(nuki->getBleAddress());
nuki->update();
}
if(openerEnabled)
{
bleScanner->whitelist(nukiOpener->getBleAddress());
nukiOpener->update();
}
}
if(lockEnabled)
{
nuki->update();
}
if(openerEnabled)
{
nukiOpener->update();
}
if(espMillis() - nukiLoopTs > 120000)
{
Log->println("nukiTask is running");
@@ -241,7 +252,6 @@ void bootloopDetection()
if(esp_reset_reason() == esp_reset_reason_t::ESP_RST_PANIC ||
esp_reset_reason() == esp_reset_reason_t::ESP_RST_INT_WDT ||
esp_reset_reason() == esp_reset_reason_t::ESP_RST_TASK_WDT ||
true ||
esp_reset_reason() == esp_reset_reason_t::ESP_RST_WDT)
{
bootloopCounter++;
@@ -400,10 +410,13 @@ void setupTasks(bool ota)
}
else
{
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1);
esp_task_wdt_add(networkTaskHandle);
if(!disableNetwork)
{
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
if(!network->isApOpen())
if(!network->isApOpen() && (lockEnabled || openerEnabled))
{
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 0);
esp_task_wdt_add(nukiTaskHandle);
@@ -414,12 +427,16 @@ void setupTasks(bool ota)
void setup()
{
//Set Log level to error for all TAGS
esp_log_level_set("*", ESP_LOG_ERROR);
//Set Log level to none for mqtt TAG
esp_log_level_set("mqtt", ESP_LOG_NONE);
//Start Serial and setup Log class
Serial.begin(115200);
Log = &Serial;
#ifndef NUKI_HUB_UPDATER
//
stdout = funopen(NULL, NULL, &write_fn, NULL, NULL);
static char linebuf[1024];
setvbuf(stdout, linebuf, _IOLBF, sizeof(linebuf));
@@ -435,6 +452,17 @@ void setup()
initializeRestartReason();
//default disableNetwork RTC_ATTR to false on power-on
if(espRunning != 1)
{
espRunning = 1;
forceEnableWebServer = false;
disableNetwork = false;
wifiFallback = false;
ethCriticalFailure = false;
}
//determine if an OTA update was requested
if((partitionType==1 && preferences->getString(preference_ota_updater_url, "").length() > 0) || (partitionType==2 && preferences->getString(preference_ota_main_url, "").length() > 0))
{
doOta = true;
@@ -496,7 +524,7 @@ void setup()
deviceIdOpener->assignId(deviceIdLock->get());
}
char16_t buffer_size = preferences->getInt(preference_buffer_size, 4096);
char16_t buffer_size = preferences->getInt(preference_buffer_size, CHAR_BUFFER_SIZE);
CharBuffer::initialize(buffer_size);
gpio = new Gpio(preferences);
@@ -520,26 +548,26 @@ void setup()
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);
nukiOfficial = new NukiOfficial(preferences);
networkLock = new NukiNetworkLock(network, nukiOfficial, preferences, CharBuffer::get(), buffer_size);
networkLock->initialize();
if(openerEnabled)
if(lockEnabled || openerEnabled)
{
networkOpener = new NukiNetworkOpener(network, preferences, CharBuffer::get(), buffer_size);
networkOpener->initialize();
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);
}
Log->println(lockEnabled ? F("Nuki Lock enabled") : F("Nuki Lock disabled"));
if(lockEnabled)
{
nukiOfficial = new NukiOfficial(preferences);
networkLock = new NukiNetworkLock(network, nukiOfficial, preferences, CharBuffer::get(), buffer_size);
if(!disableNetwork)
{
networkLock->initialize();
}
nuki = new NukiWrapper("NukiHub", deviceIdLock, bleScanner, networkLock, nukiOfficial, gpio, preferences);
nuki->initialize(firstStart);
}
@@ -547,41 +575,47 @@ void setup()
Log->println(openerEnabled ? F("Nuki Opener enabled") : F("Nuki Opener disabled"));
if(openerEnabled)
{
networkOpener = new NukiNetworkOpener(network, preferences, CharBuffer::get(), buffer_size);
if(!disableNetwork)
{
networkOpener->initialize();
}
nukiOpener = new NukiOpenerWrapper("NukiHub", deviceIdOpener, bleScanner, networkOpener, gpio, preferences);
nukiOpener->initialize();
}
if(forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true) || preferences->getBool(preference_webserial_enabled, false))
if(!doOta && !disableNetwork && (forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true) || preferences->getBool(preference_webserial_enabled, false)))
{
if(!doOta)
psychicServer = new PsychicHttpServer;
psychicServer->config.max_uri_handlers = 40;
psychicServer->config.stack_size = HTTPD_TASK_SIZE;
psychicServer->maxUploadSize = 8192;
psychicServer->maxRequestBodySize = 8192;
psychicServer->listen(80);
if(forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true))
{
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, psychicServer);
webCfgServer->initialize();
psychicServer->onNotFound([](PsychicRequest* request)
{
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType, psychicServer);
webCfgServer->initialize();
psychicServer->onNotFound([](PsychicRequest* request)
{
return request->redirect("/");
});
}
/*
#ifdef DEBUG_NUKIHUB
else psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/webserial"); });
if(preferences->getBool(preference_webserial_enabled, false))
{
WebSerial.setAuthentication(preferences->getString(preference_cred_user), preferences->getString(preference_cred_password));
WebSerial.begin(asyncServer);
WebSerial.setBuffer(1024);
}
#endif
*/
return request->redirect("/");
});
}
/*
#ifdef DEBUG_NUKIHUB
else psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/webserial"); });
if(preferences->getBool(preference_webserial_enabled, false))
{
WebSerial.setAuthentication(preferences->getString(preference_cred_user), preferences->getString(preference_cred_password));
WebSerial.begin(asyncServer);
WebSerial.setBuffer(1024);
}
#endif
*/
}
#endif

View File

@@ -1,10 +1,14 @@
#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];
extern bool ethCriticalFailure;
extern bool wifiFallback;
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),
@@ -49,6 +53,51 @@ 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."));
_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."));
_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();
@@ -57,12 +106,12 @@ const String EthernetDevice::deviceName() const
void EthernetDevice::initialize()
{
delay(250);
if(criticalEthFailure)
if(ethCriticalFailure)
{
criticalEthFailure = false;
ethCriticalFailure = 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");
wifiFallback = true;
delay(200);
restartEsp(RestartReason::NetworkDeviceCriticalFailure);
return;
@@ -73,18 +122,18 @@ void EthernetDevice::initialize()
if(_useSpi)
{
Log->println(F("Use SPI"));
criticalEthFailure = true;
ethCriticalFailure = true;
SPI.begin(_spi_sck, _spi_miso, _spi_mosi);
_hardwareInitialized = ETH.begin(_type, _phy_addr, _cs, _irq, _rst, SPI);
criticalEthFailure = false;
ethCriticalFailure = false;
}
#ifdef CONFIG_IDF_TARGET_ESP32
else
{
Log->println(F("Use RMII"));
criticalEthFailure = true;
ethCriticalFailure = true;
_hardwareInitialized = ETH.begin(_type, _phy_addr, _mdc, _mdio, _power, _clock_mode);
criticalEthFailure = false;
ethCriticalFailure = false;
if(!_ipConfiguration->dhcpEnabled())
{
_checkIpTs = espMillis() + 2000;
@@ -95,7 +144,7 @@ void EthernetDevice::initialize()
if(_hardwareInitialized)
{
Log->println(F("Ethernet hardware Initialized"));
memset(WiFi_fallbackDetect, 0, sizeof(WiFi_fallbackDetect));
wifiFallback = false;
if(_useSpi && !_ipConfiguration->dhcpEnabled())
{
@@ -111,7 +160,7 @@ void EthernetDevice::initialize()
{
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");
wifiFallback = true;
delay(200);
restartEsp(RestartReason::NetworkDeviceCriticalFailure);
return;
@@ -120,18 +169,19 @@ void EthernetDevice::initialize()
void EthernetDevice::update()
{
if(_checkIpTs != -1)
NetworkDevice::update();
if(_checkIpTs != -1 && _checkIpTs < espMillis())
{
if(_ipConfiguration->ipAddress() != ETH.localIP())
{
Log->println(F("ETH Set static IP"));
ETH.config(_ipConfiguration->ipAddress(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet(), _ipConfiguration->dnsServer());
_checkIpTs = espMillis() + 2000;
}
else
{
_checkIpTs = -1;
_checkIpTs = espMillis() + 5000;
return;
}
_checkIpTs = -1;
}
}

View File

@@ -11,6 +11,9 @@
#include <NetworkClientSecure.h>
#include <Preferences.h>
#include "NetworkDevice.h"
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#endif
class EthernetDevice : public NetworkDevice
{
@@ -45,8 +48,8 @@ public:
virtual void initialize();
virtual void reconfigure();
virtual void update();
virtual void scan(bool passive = false, bool async = true);
virtual void scan(bool passive = false, bool async = true);
virtual bool isConnected();
virtual bool isApOpen();
@@ -58,10 +61,12 @@ public:
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;
@@ -85,4 +90,10 @@ 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,6 +1,179 @@
#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,4 +1,9 @@
#pragma once
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#include "MqttClientSetup.h"
#endif
#include "IPConfiguration.h"
#include "../EspMillis.h"
@@ -14,16 +19,48 @@ public:
virtual void initialize() = 0;
virtual void reconfigure() = 0;
virtual void printError();
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;
protected:
#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
const String _hostname;
const IPConfiguration* _ipConfiguration = nullptr;
};

View File

@@ -3,14 +3,59 @@
#include "WifiDevice.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
#ifndef NUKI_HUB_UPDATER
#include "../MqttTopics.h"
#include "espMqttClient.h"
#endif
#include "../RestartReason.h"
WifiDevice::WifiDevice(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration)
: NetworkDevice(hostname, ipConfiguration),
_preferences(preferences)
{
#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."));
_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."));
_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
{
return "Built-in Wi-Fi";
@@ -373,7 +418,7 @@ void WifiDevice::onDisconnected()
}
_connecting = false;
//END QUICK RECONECT
//END QUICK RECONNECT
if(!isConnected())
{

View File

@@ -29,6 +29,7 @@ private:
void onDisconnected();
void onConnected();
bool connect();
char* _path;
Preferences* _preferences = nullptr;
@@ -44,4 +45,10 @@ private:
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
};