Arduino Core 3 (#407)

* Add and remove libs and components for Arduino Core 3

* Arduino Core 3

* Add back Solo1

* Change ESP32-S3 to 4MB build

* Update README.md

* Fix retain and number of retries

* Fix rolling log

* Fix defaults

* Fix BleScanner on Solo1

* Export settings

* Import settings

* Fix HA Battery voltage

* Change submodule

* Update espMqttClient and AsyncTCP

* Webserial and MQTT/Network reconnecting

* Update nuki_ble

---------

Co-authored-by: iranl <iranl@github.com>
This commit is contained in:
iranl
2024-07-05 18:45:39 +02:00
committed by GitHub
parent 193ebb5f91
commit 6b0100fd61
236 changed files with 16390 additions and 9740 deletions

6
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
# This file was automatically generated for projects
# without default 'CMakeLists.txt' file.
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
idf_component_register(SRCS ${app_sources})

View File

@@ -5,30 +5,39 @@
#define NUKI_HUB_VERSION "8.35"
#define NUKI_HUB_BUILD "unknownbuildnr"
#define GITHUB_LATEST_RELEASE_URL "https://github.com/technyon/nuki_hub/releases/latest"
#define GITHUB_LATEST_RELEASE_API_URL "https://api.github.com/repos/technyon/nuki_hub/releases/latest"
#define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest"
#define GITHUB_LATEST_RELEASE_API_URL (char*)"https://api.github.com/repos/technyon/nuki_hub/releases/latest"
#if defined(CONFIG_IDF_TARGET_ESP32C3)
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32c3.bin"
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32c3.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_updater_esp32c3.bin"
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32s3.bin"
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32s3.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_updater_esp32s3.bin"
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32c6.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_updater_esp32c6.bin"
#else
#if defined(FRAMEWORK_ARDUINO_SOLO1)
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32solo1.bin"
#else
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32solo1.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_updater_esp32solo1.bin"
#else
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_updater_esp32.bin"
#endif
#endif
#ifndef NUKI_HUB_UPDATER
#define MQTT_QOS_LEVEL 1
#define MQTT_CLEAN_SESSIONS false
#define MQTT_KEEP_ALIVE 60
#define GPIO_DEBOUNCE_TIME 200
#define CHAR_BUFFER_SIZE 4096
#define NETWORK_TASK_SIZE 12288
#define NUKI_TASK_SIZE 8192
#define PD_TASK_SIZE 1024
#define MAX_AUTHLOG 5
#define MAX_KEYPAD 10
#define MAX_TIMECONTROL 10
#endif
#define NETWORK_TASK_SIZE 12288

View File

@@ -5,7 +5,7 @@
#include "Logger.h"
#include "PreferencesKeys.h"
#include "RestartReason.h"
#include "../lib/gpio2go/src/Gpio2Go.h"
#include "Gpio2Go.h"
Gpio* Gpio::_inst = nullptr;
unsigned long Gpio::_debounceTs = 0;

View File

@@ -1,7 +1,13 @@
#ifndef NUKI_HUB_UPDATER
#ifndef MQTT_LOGGER_GLOBAL
#define MQTT_LOGGER_GLOBAL
#include "MqttLogger.h"
#include "WebSerial.h"
extern Print* Log;
#endif
#else
#include <Print.h>
extern Print* Log;
#endif

View File

@@ -14,7 +14,7 @@
#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_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"
@@ -93,6 +93,7 @@
#define mqtt_topic_info_nuki_hub_ip "/info/nukiHubIp"
#define mqtt_topic_reset "/maintenance/reset"
#define mqtt_topic_update "/maintenance/update"
#define mqtt_topic_webserver_state "/maintenance/webserver/state"
#define mqtt_topic_webserver_action "/maintenance/webserver/enable"
#define mqtt_topic_uptime "/maintenance/uptime"

View File

@@ -1,3 +1,4 @@
#include <string>
#include <cstring>
#include <Arduino.h>
#include "NukiDeviceId.h"

View File

@@ -1,25 +1,34 @@
#include "Network.h"
#include "NukiNetwork.h"
#include "PreferencesKeys.h"
#include "networkDevices/W5500Device.h"
#include "networkDevices/WifiDevice.h"
#include "Logger.h"
#include "Config.h"
#include <ArduinoJson.h>
#include "RestartReason.h"
#if defined(CONFIG_IDF_TARGET_ESP32)
#include "networkDevices/EthLan8720Device.h"
#endif
Network* Network::_inst = nullptr;
unsigned long Network::_ignoreSubscriptionsTs = 0;
#ifndef NUKI_HUB_UPDATER
#include <ArduinoJson.h>
bool _versionPublished = false;
#endif
NukiNetwork* NukiNetwork::_inst = nullptr;
RTC_NOINIT_ATTR char WiFi_fallbackDetect[14];
Network::Network(Preferences *preferences, PresenceDetection* presenceDetection, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize)
#ifndef NUKI_HUB_UPDATER
NukiNetwork::NukiNetwork(Preferences *preferences, PresenceDetection* presenceDetection, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize)
: _preferences(preferences),
_presenceDetection(presenceDetection),
_gpio(gpio),
_buffer(buffer),
_bufferSize(bufferSize)
#else
NukiNetwork::NukiNetwork(Preferences *preferences)
: _preferences(preferences)
#endif
{
// Remove obsolete W5500 hardware detection configuration
if(_preferences->getInt(preference_network_hardware_gpio) != 0)
@@ -30,6 +39,7 @@ Network::Network(Preferences *preferences, PresenceDetection* presenceDetection,
_inst = this;
_hostname = _preferences->getString(preference_hostname);
#ifndef NUKI_HUB_UPDATER
memset(_maintenancePathPrefix, 0, sizeof(_maintenancePathPrefix));
size_t len = maintenancePathPrefix.length();
for(int i=0; i < len; i++)
@@ -46,11 +56,12 @@ Network::Network(Preferences *preferences, PresenceDetection* presenceDetection,
{
_mqttConnectionStateTopic[i] = connectionStateTopic.charAt(i);
}
#endif
setupDevice();
}
void Network::setupDevice()
void NukiNetwork::setupDevice()
{
_ipConfiguration = new IPConfiguration(_preferences);
@@ -94,6 +105,7 @@ void Network::setupDevice()
Log->println(F("W5500 on M5Stack Atom POE"));
_networkDeviceType = NetworkDeviceType::W5500;
break;
#if defined(CONFIG_IDF_TARGET_ESP32)
case 4:
Log->println(F("Olimex ESP32-POE / ESP-POE-ISO"));
_networkDeviceType = NetworkDeviceType::Olimex_LAN8720;
@@ -114,6 +126,7 @@ void Network::setupDevice()
Log->println(F("GL-S10"));
_networkDeviceType = NetworkDeviceType::GL_S10;
break;
#endif
default:
Log->println(F("Unknown hardware selected, falling back to Wi-Fi."));
_networkDeviceType = NetworkDeviceType::WiFi;
@@ -126,6 +139,7 @@ void Network::setupDevice()
case NetworkDeviceType::W5500:
_device = new W5500Device(_hostname, _preferences, _ipConfiguration, hardwareDetect);
break;
#if defined(CONFIG_IDF_TARGET_ESP32)
case NetworkDeviceType::Olimex_LAN8720:
_device = new EthLan8720Device(_hostname, _preferences, _ipConfiguration, "Olimex (LAN8720)", ETH_PHY_ADDR, 12, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_TYPE, ETH_CLOCK_GPIO17_OUT);
break;
@@ -141,6 +155,7 @@ void Network::setupDevice()
case NetworkDeviceType::LilyGO_T_ETH_POE:
_device = new EthLan8720Device(_hostname, _preferences, _ipConfiguration, "LilyGO T-ETH-POE", 0, -1, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_TYPE, ETH_CLOCK_GPIO17_OUT);
break;
#endif
case NetworkDeviceType::WiFi:
_device = new WifiDevice(_hostname, _preferences, _ipConfiguration);
break;
@@ -149,6 +164,7 @@ void Network::setupDevice()
break;
}
#ifndef NUKI_HUB_UPDATER
_device->mqttOnConnect([&](bool sessionPresent)
{
onMqttConnect(sessionPresent);
@@ -157,9 +173,68 @@ void Network::setupDevice()
{
onMqttDisconnect(reason);
});
#endif
}
void Network::initialize()
void NukiNetwork::reconfigureDevice()
{
_device->reconfigure();
}
const String NukiNetwork::networkDeviceName() const
{
return _device->deviceName();
}
const String NukiNetwork::networkBSSID() const
{
return _device->BSSIDstr();
}
const NetworkDeviceType NukiNetwork::networkDeviceType()
{
return _networkDeviceType;
}
void NukiNetwork::setKeepAliveCallback(std::function<void()> reconnectTick)
{
_keepAliveCallback = reconnectTick;
}
void NukiNetwork::clearWifiFallback()
{
memset(WiFi_fallbackDetect, 0, sizeof(WiFi_fallbackDetect));
}
NetworkDevice *NukiNetwork::device()
{
return _device;
}
#ifdef NUKI_HUB_UPDATER
void NukiNetwork::initialize()
{
_hostname = _preferences->getString(preference_hostname);
if(_hostname == "")
{
_hostname = "nukihub";
_preferences->putString(preference_hostname, _hostname);
}
strcpy(_hostnameArr, _hostname.c_str());
_device->initialize();
Log->print(F("Host name: "));
Log->println(_hostname);
}
bool NukiNetwork::update()
{
_device->update();
return true;
}
#else
void NukiNetwork::initialize()
{
_restartOnDisconnect = _preferences->getBool(preference_restart_on_disconnect, false);
_rssiPublishInterval = _preferences->getInt(preference_rssi_publish_interval) * 1000;
@@ -219,6 +294,7 @@ void Network::initialize()
_device->mqttSetClientId(_hostnameArr);
_device->mqttSetCleanSession(MQTT_CLEAN_SESSIONS);
_device->mqttSetKeepAlive(MQTT_KEEP_ALIVE);
_networkTimeout = _preferences->getInt(preference_network_timeout);
if(_networkTimeout == 0)
@@ -261,6 +337,8 @@ void Network::initialize()
buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pinEntry.pin)).c_str(), mqtt_topic_gpio_state});
subscribe(_lockPath.c_str(), gpioPath);
break;
default:
break;
}
}
_gpio->addCallback([this](const GpioAction& action, const int& pin)
@@ -269,7 +347,7 @@ void Network::initialize()
});
}
bool Network::update()
bool NukiNetwork::update()
{
unsigned long ts = millis();
@@ -282,6 +360,8 @@ bool Network::update()
if(!_device->isConnected())
{
_device->mqttDisconnect(true);
if(_restartOnDisconnect && millis() > 60000)
{
restartEsp(RestartReason::RestartOnDisconnectWatchdog);
@@ -306,10 +386,9 @@ bool Network::update()
Log->println(F("Reconnect failed"));
break;
}
}
if(!_device->mqttConnected())
if(!_device->mqttConnected() && _device->isConnected())
{
if(_networkTimeout > 0 && (ts - _lastConnectedTs > _networkTimeout * 1000) && ts > 60000)
{
@@ -323,16 +402,17 @@ bool Network::update()
{
return false;
}
delay(2000);
}
if(!_device->mqttConnected() || !_device->isConnected()) return false;
_lastConnectedTs = ts;
if(_presenceDetection != nullptr && (_lastPresenceTs == 0 || (ts - _lastPresenceTs) > 3000))
{
char* presenceCsv = _presenceDetection->generateCsv();
// if(_presenceCsv != nullptr && strlen(_presenceCsv) > 0)
bool success = publishString(_mqttPresencePrefix, mqtt_topic_presence, presenceCsv);
bool success = publishString(_mqttPresencePrefix, mqtt_topic_presence, presenceCsv, true);
if(!success)
{
Log->println(F("Failed to publish presence CSV data."));
@@ -349,25 +429,25 @@ bool Network::update()
if(rssi != _lastRssi)
{
publishInt(_maintenancePathPrefix, mqtt_topic_wifi_rssi, _device->signalStrength());
publishInt(_maintenancePathPrefix, mqtt_topic_wifi_rssi, _device->signalStrength(), true);
_lastRssi = rssi;
}
}
if(_lastMaintenanceTs == 0 || (ts - _lastMaintenanceTs) > 30000)
{
publishULong(_maintenancePathPrefix, mqtt_topic_uptime, ts / 1000 / 60);
publishString(_maintenancePathPrefix, mqtt_topic_mqtt_connection_state, "online");
publishULong(_maintenancePathPrefix, mqtt_topic_uptime, ts / 1000 / 60, true);
publishString(_maintenancePathPrefix, mqtt_topic_mqtt_connection_state, "online", true);
if(_publishDebugInfo)
{
publishUInt(_maintenancePathPrefix, mqtt_topic_freeheap, esp_get_free_heap_size());
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_fw, getRestartReason().c_str());
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_esp, getEspRestartReason().c_str());
publishUInt(_maintenancePathPrefix, mqtt_topic_freeheap, esp_get_free_heap_size(), true);
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_fw, getRestartReason().c_str(), true);
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_esp, getEspRestartReason().c_str(), true);
}
if (!_versionPublished) {
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_version, NUKI_HUB_VERSION);
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_build, NUKI_HUB_BUILD);
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_version, NUKI_HUB_VERSION, true);
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_build, NUKI_HUB_BUILD, true);
_versionPublished = true;
}
_lastMaintenanceTs = ts;
@@ -392,7 +472,7 @@ bool Network::update()
if (!jsonError)
{
_latestVersion = doc["tag_name"];
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_latest, _latestVersion);
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_latest, _latestVersion, true);
if (_latestVersion != _preferences->getString(preference_latest_version).c_str())
{
@@ -429,14 +509,14 @@ bool Network::update()
}
void Network::onMqttConnect(const bool &sessionPresent)
void NukiNetwork::onMqttConnect(const bool &sessionPresent)
{
_connectReplyReceived = true;
}
void Network::onMqttDisconnect(const espMqttClientTypes::DisconnectReason &reason)
void NukiNetwork::onMqttDisconnect(const espMqttClientTypes::DisconnectReason &reason)
{
_connectReplyReceived = true;
_connectReplyReceived = false;
Log->print("MQTT disconnected. Reason: ");
switch(reason)
@@ -471,7 +551,7 @@ void Network::onMqttDisconnect(const espMqttClientTypes::DisconnectReason &reaso
}
}
bool Network::reconnect()
bool NukiNetwork::reconnect()
{
_mqttConnectionState = 0;
int port = _preferences->getInt(preference_mqtt_broker_port);
@@ -521,8 +601,7 @@ bool Network::reconnect()
_mqttConnectionState = 1;
delay(100);
_ignoreSubscriptionsTs = millis() + 2000;
_device->mqttOnMessage(Network::onMqttDataReceivedCallback);
_device->mqttOnMessage(NukiNetwork::onMqttDataReceivedCallback);
for(const String& topic : _subscribedTopics)
{
_device->mqttSubscribe(topic.c_str(), MQTT_QOS_LEVEL);
@@ -530,15 +609,15 @@ bool Network::reconnect()
if(_firstConnect)
{
_firstConnect = false;
publishString(_maintenancePathPrefix, mqtt_topic_network_device, _device->deviceName().c_str());
publishString(_maintenancePathPrefix, mqtt_topic_network_device, _device->deviceName().c_str(), true);
for(const auto& it : _initTopics)
{
_device->mqttPublish(it.first.c_str(), MQTT_QOS_LEVEL, true, it.second.c_str());
}
}
publishString(_maintenancePathPrefix, mqtt_topic_mqtt_connection_state, "online");
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_ip, _device->localIP().c_str());
publishString(_maintenancePathPrefix, mqtt_topic_mqtt_connection_state, "online", true);
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_ip, _device->localIP().c_str(), true);
_mqttConnectionState = 2;
for(const auto& callback : _reconnectedCallbacks)
@@ -552,20 +631,20 @@ bool Network::reconnect()
_device->printError();
_mqttConnectionState = 0;
_nextReconnect = millis() + 5000;
_device->mqttDisconnect(true);
//_device->mqttDisconnect(true);
}
}
return _mqttConnectionState > 0;
}
void Network::subscribe(const char* prefix, const char *path)
void NukiNetwork::subscribe(const char* prefix, const char *path)
{
char prefixedPath[500];
buildMqttPath(prefixedPath, { prefix, path });
_subscribedTopics.push_back(prefixedPath);
}
void Network::initTopic(const char *prefix, const char *path, const char *value)
void NukiNetwork::initTopic(const char *prefix, const char *path, const char *value)
{
char prefixedPath[500];
buildMqttPath(prefixedPath, { prefix, path });
@@ -574,7 +653,7 @@ void Network::initTopic(const char *prefix, const char *path, const char *value)
_initTopics[pathStr] = valueStr;
}
void Network::buildMqttPath(char* outPath, std::initializer_list<const char*> paths)
void NukiNetwork::buildMqttPath(char* outPath, std::initializer_list<const char*> paths)
{
int offset = 0;
int pathCount = 0;
@@ -600,12 +679,12 @@ void Network::buildMqttPath(char* outPath, std::initializer_list<const char*> pa
outPath[offset] = 0x00;
}
void Network::registerMqttReceiver(MqttReceiver* receiver)
void NukiNetwork::registerMqttReceiver(MqttReceiver* receiver)
{
_mqttReceivers.push_back(receiver);
}
void Network::onMqttDataReceivedCallback(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total)
void NukiNetwork::onMqttDataReceivedCallback(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total)
{
uint8_t value[800] = {0};
@@ -619,15 +698,10 @@ void Network::onMqttDataReceivedCallback(const espMqttClientTypes::MessageProper
_inst->onMqttDataReceived(properties, topic, value, len, index, total);
}
void Network::onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total)
void NukiNetwork::onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total)
{
parseGpioTopics(properties, topic, payload, len, index, total);
if(millis() < _ignoreSubscriptionsTs)
{
return;
}
for(auto receiver : _mqttReceivers)
{
receiver->onMqttDataReceived(topic, (byte*)payload, index);
@@ -635,7 +709,7 @@ void Network::onMqttDataReceived(const espMqttClientTypes::MessageProperties& pr
}
void Network::parseGpioTopics(const espMqttClientTypes::MessageProperties &properties, const char *topic, const uint8_t *payload, size_t& len, size_t& index, size_t& total)
void NukiNetwork::parseGpioTopics(const espMqttClientTypes::MessageProperties &properties, const char *topic, const uint8_t *payload, size_t& len, size_t& index, size_t& total)
{
char gpioPath[250];
buildMqttPath(gpioPath, {_lockPath.c_str(), mqtt_topic_gpio_prefix, mqtt_topic_gpio_pin});
@@ -665,49 +739,34 @@ void Network::parseGpioTopics(const espMqttClientTypes::MessageProperties &prope
}
}
void Network::gpioActionCallback(const GpioAction &action, const int &pin)
void NukiNetwork::gpioActionCallback(const GpioAction &action, const int &pin)
{
_gpioTs[pin] = millis();
}
void Network::reconfigureDevice()
{
_device->reconfigure();
}
void Network::setMqttPresencePath(char *path)
void NukiNetwork::setMqttPresencePath(char *path)
{
memset(_mqttPresencePrefix, 0, sizeof(_mqttPresencePrefix));
strcpy(_mqttPresencePrefix, path);
}
void Network::disableAutoRestarts()
void NukiNetwork::disableAutoRestarts()
{
_networkTimeout = 0;
_restartOnDisconnect = false;
}
int Network::mqttConnectionState()
int NukiNetwork::mqttConnectionState()
{
return _mqttConnectionState;
}
bool Network::encryptionSupported()
bool NukiNetwork::encryptionSupported()
{
return _device->supportsEncryption();
}
const String Network::networkDeviceName() const
{
return _device->deviceName();
}
const String Network::networkBSSID() const
{
return _device->BSSIDstr();
}
void Network::publishFloat(const char* prefix, const char* topic, const float value, const uint8_t precision, bool retain)
void NukiNetwork::publishFloat(const char* prefix, const char* topic, const float value, const uint8_t precision, bool retain)
{
char str[30];
dtostrf(value, 0, precision, str);
@@ -716,7 +775,7 @@ void Network::publishFloat(const char* prefix, const char* topic, const float va
_device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
}
void Network::publishInt(const char* prefix, const char *topic, const int value, bool retain)
void NukiNetwork::publishInt(const char* prefix, const char *topic, const int value, bool retain)
{
char str[30];
itoa(value, str, 10);
@@ -725,7 +784,7 @@ void Network::publishInt(const char* prefix, const char *topic, const int value,
_device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
}
void Network::publishUInt(const char* prefix, const char *topic, const unsigned int value, bool retain)
void NukiNetwork::publishUInt(const char* prefix, const char *topic, const unsigned int value, bool retain)
{
char str[30];
utoa(value, str, 10);
@@ -734,7 +793,7 @@ void Network::publishUInt(const char* prefix, const char *topic, const unsigned
_device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
}
void Network::publishULong(const char* prefix, const char *topic, const unsigned long value, bool retain)
void NukiNetwork::publishULong(const char* prefix, const char *topic, const unsigned long value, bool retain)
{
char str[30];
utoa(value, str, 10);
@@ -743,7 +802,7 @@ void Network::publishULong(const char* prefix, const char *topic, const unsigned
_device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
}
void Network::publishBool(const char* prefix, const char *topic, const bool value, bool retain)
void NukiNetwork::publishBool(const char* prefix, const char *topic, const bool value, bool retain)
{
char str[2] = {0};
str[0] = value ? '1' : '0';
@@ -752,14 +811,14 @@ void Network::publishBool(const char* prefix, const char *topic, const bool valu
_device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
}
bool Network::publishString(const char* prefix, const char *topic, const char *value, bool retain)
bool NukiNetwork::publishString(const char* prefix, const char *topic, const char *value, bool retain)
{
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
return _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, value) > 0;
}
void Network::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 NukiNetwork::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)
{
JsonDocument json;
json.clear();
@@ -843,7 +902,7 @@ void Network::publishHASSConfig(char* deviceType, const char* baseTopic, char* n
"diagnostic",
"",
{ {(char*)"unit_of_meas", (char*)"V"},
{(char*)"val_tpl", (char*)"{{value_json.level}}" }});
{(char*)"val_tpl", (char*)"{{value_json.batteryVoltage}}" }});
// Trigger
publishHassTopic("sensor",
@@ -991,23 +1050,47 @@ void Network::publishHASSConfig(char* deviceType, const char* baseTopic, char* n
_lockPath.toCharArray(latest_version_topic,_lockPath.length() + 1);
strcat(latest_version_topic, mqtt_topic_info_nuki_hub_latest);
publishHassTopic("update",
"nuki_hub_update",
uidString,
"_nuki_hub_update",
"NUKI Hub firmware update",
name,
baseTopic,
_lockPath + mqtt_topic_info_nuki_hub_version,
deviceType,
"firmware",
"",
"diagnostic",
"",
{ { (char*)"en", (char*)"true" },
{ (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
{ (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
{ (char*)"l_ver_t", (char*)latest_version_topic }});
if(!_preferences->getBool(preference_update_from_mqtt, false))
{
publishHassTopic("update",
"nuki_hub_update",
uidString,
"_nuki_hub_update",
"NUKI Hub firmware update",
name,
baseTopic,
_lockPath + mqtt_topic_info_nuki_hub_version,
deviceType,
"firmware",
"",
"diagnostic",
"",
{ { (char*)"en", (char*)"true" },
{ (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
{ (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
{ (char*)"l_ver_t", (char*)latest_version_topic }});
}
else
{
publishHassTopic("update",
"nuki_hub_update",
uidString,
"_nuki_hub_update",
"NUKI Hub firmware update",
name,
baseTopic,
_lockPath + mqtt_topic_info_nuki_hub_version,
deviceType,
"firmware",
"",
"diagnostic",
_lockPath + mqtt_topic_update,
{ { (char*)"en", (char*)"true" },
{ (char*)"pl_inst", (char*)"1" },
{ (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
{ (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
{ (char*)"l_ver_t", (char*)latest_version_topic }});
}
}
else
{
@@ -1099,8 +1182,7 @@ void Network::publishHASSConfig(char* deviceType, const char* baseTopic, char* n
{ {(char*)"unit_of_meas", (char*)"dBm"} });
}
void Network::publishHASSConfigAdditionalLockEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
void NukiNetwork::publishHASSConfigAdditionalLockEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
{
uint32_t aclPrefs[17];
_preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
@@ -2150,7 +2232,7 @@ void Network::publishHASSConfigAdditionalLockEntities(char *deviceType, const ch
}
}
void Network::publishHASSConfigDoorSensor(char *deviceType, const char *baseTopic, char *name, char *uidString)
void NukiNetwork::publishHASSConfigDoorSensor(char *deviceType, const char *baseTopic, char *name, char *uidString)
{
publishHassTopic("binary_sensor",
"door_sensor",
@@ -2170,7 +2252,7 @@ void Network::publishHASSConfigDoorSensor(char *deviceType, const char *baseTopi
{(char*)"pl_not_avail", (char*)"unavailable"}});
}
void Network::publishHASSConfigAdditionalOpenerEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
void NukiNetwork::publishHASSConfigAdditionalOpenerEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
{
uint32_t aclPrefs[17];
_preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
@@ -3027,7 +3109,7 @@ void Network::publishHASSConfigAdditionalOpenerEntities(char *deviceType, const
}
}
void Network::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic, char *name, char *uidString)
void NukiNetwork::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic, char *name, char *uidString)
{
publishHassTopic("sensor",
"last_action_authorization",
@@ -3064,10 +3146,10 @@ void Network::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic
"",
{ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
{ (char*)"json_attr_t", (char*)rollingStateChr },
{ (char*)"val_tpl", (char*)"{{value_json.authorizationId}}" }});
{ (char*)"val_tpl", (char*)"{{value_json.index}}" }});
}
void Network::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, char *name, char *uidString)
void NukiNetwork::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, char *name, char *uidString)
{
// Keypad battery critical
publishHassTopic("binary_sensor",
@@ -3121,7 +3203,7 @@ void Network::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, c
{ (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'KeypadAction')|first|default).completionStatus|default }}" }});
}
void Network::publishHASSWifiRssiConfig(char *deviceType, const char *baseTopic, char *name, char *uidString)
void NukiNetwork::publishHASSWifiRssiConfig(char *deviceType, const char *baseTopic, char *name, char *uidString)
{
if(_device->signalStrength() == 127)
{
@@ -3144,7 +3226,7 @@ void Network::publishHASSWifiRssiConfig(char *deviceType, const char *baseTopic,
{ {(char*)"unit_of_meas", (char*)"dBm"} });
}
void Network::publishHassTopic(const String& mqttDeviceType,
void NukiNetwork::publishHassTopic(const String& mqttDeviceType,
const String& mqttDeviceName,
const String& uidString,
const String& uidStringPostfix,
@@ -3172,7 +3254,7 @@ void Network::publishHassTopic(const String& mqttDeviceType,
}
}
String Network::createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
String NukiNetwork::createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
{
String discoveryTopic = _preferences->getString(preference_mqtt_hass_discovery);
String path = discoveryTopic;
@@ -3187,7 +3269,7 @@ String Network::createHassTopicPath(const String& mqttDeviceType, const String&
return path;
}
void Network::removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
void NukiNetwork::removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
{
String discoveryTopic = _preferences->getString(preference_mqtt_hass_discovery);
@@ -3198,7 +3280,7 @@ void Network::removeHassTopic(const String& mqttDeviceType, const String& mqttDe
}
}
void Network::removeTopic(const String& mqttPath, const String& mqttTopic)
void NukiNetwork::removeTopic(const String& mqttPath, const String& mqttTopic)
{
String path = mqttPath;
path.concat(mqttTopic);
@@ -3211,7 +3293,7 @@ void Network::removeTopic(const String& mqttPath, const String& mqttTopic)
}
void Network::removeHASSConfig(char* uidString)
void NukiNetwork::removeHASSConfig(char* uidString)
{
removeHassTopic((char*)"lock", (char*)"smartlock", uidString);
removeHassTopic((char*)"binary_sensor", (char*)"battery_low", uidString);
@@ -3300,12 +3382,12 @@ void Network::removeHASSConfig(char* uidString)
removeHassTopic((char*)"switch", (char*)"auto_unlatch", uidString);
}
void Network::removeHASSConfigTopic(char *deviceType, char *name, char *uidString)
void NukiNetwork::removeHASSConfigTopic(char *deviceType, char *name, char *uidString)
{
removeHassTopic(deviceType, name, uidString);
}
JsonDocument Network::createHassJson(const String& uidString,
JsonDocument NukiNetwork::createHassJson(const String& uidString,
const String& uidStringPostfix,
const String& displayName,
const String& name,
@@ -3377,7 +3459,7 @@ JsonDocument Network::createHassJson(const String& uidString,
return json;
}
void Network::batteryTypeToString(const Nuki::BatteryType battype, char* str) {
void NukiNetwork::batteryTypeToString(const Nuki::BatteryType battype, char* str) {
switch (battype) {
case Nuki::BatteryType::Alkali:
strcpy(str, "Alkali");
@@ -3394,7 +3476,7 @@ void Network::batteryTypeToString(const Nuki::BatteryType battype, char* str) {
}
}
void Network::advertisingModeToString(const Nuki::AdvertisingMode advmode, char* str) {
void NukiNetwork::advertisingModeToString(const Nuki::AdvertisingMode advmode, char* str) {
switch (advmode) {
case Nuki::AdvertisingMode::Automatic:
strcpy(str, "Automatic");
@@ -3414,7 +3496,7 @@ void Network::advertisingModeToString(const Nuki::AdvertisingMode advmode, char*
}
}
void Network::timeZoneIdToString(const Nuki::TimeZoneId timeZoneId, char* str) {
void NukiNetwork::timeZoneIdToString(const Nuki::TimeZoneId timeZoneId, char* str) {
switch (timeZoneId) {
case Nuki::TimeZoneId::Africa_Cairo:
strcpy(str, "Africa/Cairo");
@@ -3563,38 +3645,19 @@ void Network::timeZoneIdToString(const Nuki::TimeZoneId timeZoneId, char* str) {
}
}
const NetworkDeviceType Network::networkDeviceType()
{
return _networkDeviceType;
}
uint16_t Network::subscribe(const char *topic, uint8_t qos)
uint16_t NukiNetwork::subscribe(const char *topic, uint8_t qos)
{
return _device->mqttSubscribe(topic, qos);
}
void Network::setKeepAliveCallback(std::function<void()> reconnectTick)
{
_keepAliveCallback = reconnectTick;
}
void Network::addReconnectedCallback(std::function<void()> reconnectedCallback)
void NukiNetwork::addReconnectedCallback(std::function<void()> reconnectedCallback)
{
_reconnectedCallbacks.push_back(reconnectedCallback);
}
void Network::clearWifiFallback()
{
memset(WiFi_fallbackDetect, 0, sizeof(WiFi_fallbackDetect));
}
void Network::disableMqtt()
void NukiNetwork::disableMqtt()
{
_device->disableMqtt();
_mqttEnabled = false;
}
NetworkDevice *Network::device()
{
return _device;
}
#endif

View File

@@ -4,14 +4,17 @@
#include <vector>
#include <map>
#include "networkDevices/NetworkDevice.h"
#include "MqttReceiver.h"
#include "networkDevices/IPConfiguration.h"
#include <HTTPClient.h>
#ifndef NUKI_HUB_UPDATER
#include "MqttReceiver.h"
#include "MqttTopics.h"
#include "Gpio.h"
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include "NukiConstants.h"
#include "PresenceDetection.h"
#endif
enum class NetworkDeviceType
{
@@ -26,20 +29,27 @@ enum class NetworkDeviceType
#define JSON_BUFFER_SIZE 1024
class Network
class NukiNetwork
{
public:
explicit Network(Preferences* preferences,
PresenceDetection* presenceDetection,
Gpio* gpio,
const String& maintenancePathPrefix,
char* buffer,
size_t bufferSize);
void initialize();
bool update();
void registerMqttReceiver(MqttReceiver* receiver);
void reconfigureDevice();
void clearWifiFallback();
const String networkDeviceName() const;
const String networkBSSID() const;
const NetworkDeviceType networkDeviceType();
void setKeepAliveCallback(std::function<void()> reconnectTick);
NetworkDevice* device();
#ifdef NUKI_HUB_UPDATER
explicit NukiNetwork(Preferences* preferences);
#else
explicit NukiNetwork(Preferences* preferences, PresenceDetection* presenceDetection, Gpio* gpio, const String& maintenancePathPrefix, char* buffer, size_t bufferSize);
void registerMqttReceiver(MqttReceiver* receiver);
void setMqttPresencePath(char* path);
void disableAutoRestarts(); // disable on OTA start
void disableMqtt();
@@ -83,29 +93,38 @@ public:
void advertisingModeToString(const Nuki::AdvertisingMode advmode, char* str);
void timeZoneIdToString(const Nuki::TimeZoneId timeZoneId, char* str);
void clearWifiFallback();
int mqttConnectionState(); // 0 = not connected; 1 = connected; 2 = connected and mqtt processed
bool encryptionSupported();
const String networkDeviceName() const;
const String networkBSSID() const;
const NetworkDeviceType networkDeviceType();
uint16_t subscribe(const char* topic, uint8_t qos);
void setKeepAliveCallback(std::function<void()> reconnectTick);
void addReconnectedCallback(std::function<void()> reconnectedCallback);
NetworkDevice* device();
#endif
private:
void setupDevice();
bool reconnect();
static NukiNetwork* _inst;
const char* _latestVersion;
HTTPClient https;
Preferences* _preferences;
IPConfiguration* _ipConfiguration = nullptr;
String _hostname;
char _hostnameArr[101] = {0};
NetworkDevice* _device = nullptr;
std::function<void()> _keepAliveCallback = nullptr;
std::vector<std::function<void()>> _reconnectedCallbacks;
NetworkDeviceType _networkDeviceType = (NetworkDeviceType)-1;
#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);
void gpioActionCallback(const GpioAction& action, const int& pin);
void setupDevice();
bool reconnect();
String createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
JsonDocument createHassJson(const String& uidString,
@@ -127,22 +146,13 @@ private:
void buildMqttPath(char* outPath, std::initializer_list<const char*> paths);
static Network* _inst;
const char* _lastWillPayload = "offline";
char _mqttConnectionStateTopic[211] = {0};
String _lockPath;
const char* _latestVersion;
HTTPClient https;
Preferences* _preferences;
PresenceDetection* _presenceDetection;
Gpio* _gpio;
IPConfiguration* _ipConfiguration = nullptr;
String _hostname;
char _hostnameArr[101] = {0};
NetworkDevice* _device = nullptr;
int _mqttConnectionState = 0;
bool _connectReplyReceived = false;
@@ -166,18 +176,12 @@ private:
unsigned long _lastPresenceTs = 0;
unsigned long _lastRssiTs = 0;
bool _mqttEnabled = true;
static unsigned long _ignoreSubscriptionsTs;
long _rssiPublishInterval = 0;
std::map<uint8_t, unsigned long> _gpioTs;
char* _buffer;
const size_t _bufferSize;
std::function<void()> _keepAliveCallback = nullptr;
std::vector<std::function<void()>> _reconnectedCallbacks;
NetworkDeviceType _networkDeviceType = (NetworkDeviceType)-1;
int8_t _lastRssi = 127;
};
#endif
};

View File

@@ -1,6 +1,7 @@
#include "NetworkLock.h"
#include "NukiNetworkLock.h"
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include "Arduino.h"
#include "Config.h"
#include "MqttTopics.h"
#include "PreferencesKeys.h"
#include "Logger.h"
@@ -8,7 +9,7 @@
#include <ArduinoJson.h>
#include <ctype.h>
NetworkLock::NetworkLock(Network* network, Preferences* preferences, char* buffer, size_t bufferSize)
NukiNetworkLock::NukiNetworkLock(NukiNetwork* network, Preferences* preferences, char* buffer, size_t bufferSize)
: _network(network),
_preferences(preferences),
_buffer(buffer),
@@ -33,11 +34,11 @@ NetworkLock::NetworkLock(Network* network, Preferences* preferences, char* buffe
_network->registerMqttReceiver(this);
}
NetworkLock::~NetworkLock()
NukiNetworkLock::~NukiNetworkLock()
{
}
void NetworkLock::initialize()
void NukiNetworkLock::initialize()
{
String mqttPath = _preferences->getString(preference_mqtt_lock_path);
if(mqttPath.length() > 0)
@@ -63,8 +64,16 @@ void NetworkLock::initialize()
_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_reset);
_network->initTopic(_mqttPath, mqtt_topic_reset, "0");
}
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0))
_network->subscribe(_mqttPath, mqtt_topic_update);
_network->initTopic(_mqttPath, mqtt_topic_update, "0");
#endif
_network->subscribe(_mqttPath, mqtt_topic_webserver_action);
_network->initTopic(_mqttPath, mqtt_topic_webserver_action, "--");
@@ -167,7 +176,7 @@ void NetworkLock::initialize()
});
}
void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
void NukiNetworkLock::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
{
char* value = (char*)payload;
@@ -178,6 +187,16 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
delay(200);
restartEsp(RestartReason::RequestedViaMqtt);
}
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0))
else if(comparePrefixedPath(topic, mqtt_topic_update) && strcmp(value, "1") == 0 && _preferences->getBool(preference_update_from_mqtt, false))
{
Log->println(F("Update requested via MQTT."));
_preferences->putString(preference_ota_updater_url, GITHUB_LATEST_UPDATER_BINARY_URL);
_preferences->putString(preference_ota_main_url, GITHUB_LATEST_RELEASE_BINARY_URL);
delay(200);
restartEsp(RestartReason::OTAReboot);
}
#endif
else if(comparePrefixedPath(topic, mqtt_topic_webserver_action))
{
if(strcmp(value, "") == 0 ||
@@ -197,7 +216,7 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
_preferences->putBool(preference_webserver_enabled, false);
}
publishString(mqtt_topic_webserver_action, "--");
publishString(mqtt_topic_webserver_action, "--", true);
_network->clearWifiFallback();
delay(200);
restartEsp(RestartReason::RequestedViaMqtt);
@@ -275,12 +294,12 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
if(strcmp(value, "--") != 0)
{
publishString(mqtt_topic_keypad_command_action, "--");
publishString(mqtt_topic_keypad_command_action, "--", true);
}
publishInt(mqtt_topic_keypad_command_id, _keypadCommandId);
publishString(mqtt_topic_keypad_command_name, _keypadCommandName);
publishString(mqtt_topic_keypad_command_code, _keypadCommandCode);
publishInt(mqtt_topic_keypad_command_enabled, _keypadCommandEnabled);
publishInt(mqtt_topic_keypad_command_id, _keypadCommandId, true);
publishString(mqtt_topic_keypad_command_name, _keypadCommandName, true);
publishString(mqtt_topic_keypad_command_code, _keypadCommandCode, true);
publishInt(mqtt_topic_keypad_command_enabled, _keypadCommandEnabled, true);
}
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_id))
@@ -304,22 +323,22 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_CONFIG;
publishString(mqtt_topic_query_config, "0");
publishString(mqtt_topic_query_config, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_LOCKSTATE;
publishString(mqtt_topic_query_lockstate, "0");
publishString(mqtt_topic_query_lockstate, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_KEYPAD;
publishString(mqtt_topic_query_keypad, "0");
publishString(mqtt_topic_query_keypad, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_BATTERY;
publishString(mqtt_topic_query_battery, "0");
publishString(mqtt_topic_query_battery, "0", true);
}
if(comparePrefixedPath(topic, mqtt_topic_config_action))
@@ -331,7 +350,7 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
_configUpdateReceivedCallback(value);
}
publishString(mqtt_topic_config_action, "--");
publishString(mqtt_topic_config_action, "--", true);
}
if(comparePrefixedPath(topic, mqtt_topic_keypad_json_action))
@@ -343,7 +362,7 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
_keypadJsonCommandReceivedReceivedCallback(value);
}
publishString(mqtt_topic_keypad_json_action, "--");
publishString(mqtt_topic_keypad_json_action, "--", true);
}
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
@@ -355,11 +374,11 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
_timeControlCommandReceivedReceivedCallback(value);
}
publishString(mqtt_topic_timecontrol_action, "--");
publishString(mqtt_topic_timecontrol_action, "--", true);
}
}
void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState)
void NukiNetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurnerState, const NukiLock::KeyTurnerState& lastKeyTurnerState)
{
char str[50];
memset(&str, 0, sizeof(str));
@@ -374,7 +393,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
if(keyTurnerState.lockState != NukiLock::LockState::Undefined)
{
publishString(mqtt_topic_lock_state, str);
publishString(mqtt_topic_lock_state, str, true);
if(_haEnabled)
{
@@ -400,7 +419,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
if(_firstTunerStatePublish || keyTurnerState.trigger != lastKeyTurnerState.trigger)
{
publishString(mqtt_topic_lock_trigger, str);
publishString(mqtt_topic_lock_trigger, str, true);
}
json["trigger"] = str;
@@ -425,7 +444,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
if(_firstTunerStatePublish || keyTurnerState.lastLockAction != lastKeyTurnerState.lastLockAction)
{
publishString(mqtt_topic_lock_last_lock_action, str);
publishString(mqtt_topic_lock_last_lock_action, str, true);
}
json["last_lock_action"] = str;
@@ -445,7 +464,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
if(_firstTunerStatePublish || keyTurnerState.lastLockActionCompletionStatus != lastKeyTurnerState.lastLockActionCompletionStatus)
{
publishString(mqtt_topic_lock_completionStatus, str);
publishString(mqtt_topic_lock_completionStatus, str, true);
}
json["lock_completion_status"] = str;
@@ -457,7 +476,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
if(_firstTunerStatePublish || keyTurnerState.doorSensorState != lastKeyTurnerState.doorSensorState)
{
publishString(mqtt_topic_lock_door_sensor_state, str);
publishString(mqtt_topic_lock_door_sensor_state, str, true);
}
json["door_sensor_state"] = str;
@@ -474,14 +493,14 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
if((_firstTunerStatePublish || keyTurnerState.criticalBatteryState != lastKeyTurnerState.criticalBatteryState) && !_preferences->getBool(preference_disable_non_json, false))
{
publishBool(mqtt_topic_battery_critical, critical);
publishBool(mqtt_topic_battery_charging, charging);
publishInt(mqtt_topic_battery_level, level);
publishBool(mqtt_topic_battery_critical, critical, true);
publishBool(mqtt_topic_battery_charging, charging, true);
publishInt(mqtt_topic_battery_level, level, true);
}
if((_firstTunerStatePublish || keyTurnerState.accessoryBatteryState != lastKeyTurnerState.accessoryBatteryState) && !_preferences->getBool(preference_disable_non_json, false))
{
publishBool(mqtt_topic_battery_keypad_critical, keypadCritical);
publishBool(mqtt_topic_battery_keypad_critical, keypadCritical, true);
}
}
else
@@ -494,55 +513,55 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
json["auth_name"] = _authName;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_lock_json, _buffer);
publishString(mqtt_topic_lock_json, _buffer, true);
serializeJson(jsonBattery, _buffer, _bufferSize);
publishString(mqtt_topic_battery_basic_json, _buffer);
publishString(mqtt_topic_battery_basic_json, _buffer, true);
_firstTunerStatePublish = false;
}
void NetworkLock::publishState(NukiLock::LockState lockState)
void NukiNetworkLock::publishState(NukiLock::LockState lockState)
{
switch(lockState)
{
case NukiLock::LockState::Locked:
publishString(mqtt_topic_lock_ha_state, "locked");
publishString(mqtt_topic_lock_binary_state, "locked");
publishString(mqtt_topic_lock_ha_state, "locked", true);
publishString(mqtt_topic_lock_binary_state, "locked", true);
break;
case NukiLock::LockState::Locking:
publishString(mqtt_topic_lock_ha_state, "locking");
publishString(mqtt_topic_lock_binary_state, "locked");
publishString(mqtt_topic_lock_ha_state, "locking", true);
publishString(mqtt_topic_lock_binary_state, "locked", true);
break;
case NukiLock::LockState::Unlocking:
publishString(mqtt_topic_lock_ha_state, "unlocking");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "unlocking", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiLock::LockState::Unlocked:
case NukiLock::LockState::UnlockedLnga:
publishString(mqtt_topic_lock_ha_state, "unlocked");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "unlocked", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiLock::LockState::Unlatched:
publishString(mqtt_topic_lock_ha_state, "open");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "open", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiLock::LockState::Unlatching:
publishString(mqtt_topic_lock_ha_state, "opening");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "opening", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiLock::LockState::Uncalibrated:
case NukiLock::LockState::Calibration:
case NukiLock::LockState::BootRun:
case NukiLock::LockState::MotorBlocked:
publishString(mqtt_topic_lock_ha_state, "jammed");
publishString(mqtt_topic_lock_ha_state, "jammed", true);
break;
default:
break;
}
}
void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>& logEntries, bool latest)
void NukiNetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>& logEntries, bool latest)
{
char str[50];
char authName[33];
@@ -659,46 +678,47 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
_lastRollingLog = log.index;
serializeJson(entry, _buffer, _bufferSize);
publishString(mqtt_topic_lock_log_rolling, _buffer);
publishInt(mqtt_topic_lock_log_rolling_last, log.index);
publishInt(mqtt_topic_lock_log_rolling_last, log.index, true);
}
}
serializeJson(json, _buffer, _bufferSize);
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer);
else publishString(mqtt_topic_lock_log, _buffer);
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer, true);
else publishString(mqtt_topic_lock_log, _buffer, true);
if(authIndex > 0)
{
publishUInt(mqtt_topic_lock_auth_id, _authId);
publishString(mqtt_topic_lock_auth_name, _authName);
publishUInt(mqtt_topic_lock_auth_id, _authId, true);
publishString(mqtt_topic_lock_auth_name, _authName, true);
}
}
void NetworkLock::clearAuthorizationInfo()
void NukiNetworkLock::clearAuthorizationInfo()
{
publishString(mqtt_topic_lock_log, "--");
publishUInt(mqtt_topic_lock_auth_id, 0);
publishString(mqtt_topic_lock_auth_name, "--");}
void NetworkLock::publishCommandResult(const char *resultStr)
{
publishString(mqtt_topic_lock_action_command_result, resultStr);
publishString(mqtt_topic_lock_log, "--", true);
publishUInt(mqtt_topic_lock_auth_id, 0, true);
publishString(mqtt_topic_lock_auth_name, "--", true);
}
void NetworkLock::publishLockstateCommandResult(const char *resultStr)
void NukiNetworkLock::publishCommandResult(const char *resultStr)
{
publishString(mqtt_topic_query_lockstate_command_result, resultStr);
publishString(mqtt_topic_lock_action_command_result, resultStr, true);
}
void NetworkLock::publishBatteryReport(const NukiLock::BatteryReport& batteryReport)
void NukiNetworkLock::publishLockstateCommandResult(const char *resultStr)
{
publishString(mqtt_topic_query_lockstate_command_result, resultStr, true);
}
void NukiNetworkLock::publishBatteryReport(const NukiLock::BatteryReport& batteryReport)
{
if(!_preferences->getBool(preference_disable_non_json, false))
{
publishFloat(mqtt_topic_battery_voltage, (float)batteryReport.batteryVoltage / 1000.0);
publishInt(mqtt_topic_battery_drain, batteryReport.batteryDrain); // milliwatt seconds
publishFloat(mqtt_topic_battery_max_turn_current, (float)batteryReport.maxTurnCurrent / 1000.0);
publishInt(mqtt_topic_battery_lock_distance, batteryReport.lockDistance); // degrees
publishFloat(mqtt_topic_battery_voltage, (float)batteryReport.batteryVoltage / 1000.0, true);
publishInt(mqtt_topic_battery_drain, batteryReport.batteryDrain, true); // milliwatt seconds
publishFloat(mqtt_topic_battery_max_turn_current, (float)batteryReport.maxTurnCurrent / 1000.0, true);
publishInt(mqtt_topic_battery_lock_distance, batteryReport.lockDistance, true); // degrees
}
char str[50];
@@ -719,10 +739,10 @@ void NetworkLock::publishBatteryReport(const NukiLock::BatteryReport& batteryRep
json["batteryResistance"] = (float)batteryReport.batteryResistance / 1000.0;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_battery_advanced_json, _buffer);
publishString(mqtt_topic_battery_advanced_json, _buffer, true);
}
void NetworkLock::publishConfig(const NukiLock::Config &config)
void NukiNetworkLock::publishConfig(const NukiLock::Config &config)
{
char str[50];
char curTime[20];
@@ -773,21 +793,21 @@ void NetworkLock::publishConfig(const NukiLock::Config &config)
json["timeZone"] = str;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_config_basic_json, _buffer);
publishString(mqtt_topic_config_basic_json, _buffer, true);
if(!_preferences->getBool(preference_disable_non_json, false))
{
publishBool(mqtt_topic_config_button_enabled, config.buttonEnabled == 1);
publishBool(mqtt_topic_config_led_enabled, config.ledEnabled == 1);
publishInt(mqtt_topic_config_led_brightness, config.ledBrightness);
publishBool(mqtt_topic_config_single_lock, config.singleLock == 1);
publishBool(mqtt_topic_config_button_enabled, config.buttonEnabled == 1, true);
publishBool(mqtt_topic_config_led_enabled, config.ledEnabled == 1, true);
publishInt(mqtt_topic_config_led_brightness, config.ledBrightness, true);
publishBool(mqtt_topic_config_single_lock, config.singleLock == 1, true);
}
publishString(mqtt_topic_info_firmware_version, std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]));
publishString(mqtt_topic_info_hardware_version, std::to_string(config.hardwareRevision[0]) + "." + std::to_string(config.hardwareRevision[1]));
publishString(mqtt_topic_info_firmware_version, std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]), true);
publishString(mqtt_topic_info_hardware_version, std::to_string(config.hardwareRevision[0]) + "." + std::to_string(config.hardwareRevision[1]), true);
}
void NetworkLock::publishAdvancedConfig(const NukiLock::AdvancedConfig &config)
void NukiNetworkLock::publishAdvancedConfig(const NukiLock::AdvancedConfig &config)
{
char str[50];
char nmst[6];
@@ -828,31 +848,31 @@ void NetworkLock::publishAdvancedConfig(const NukiLock::AdvancedConfig &config)
json["autoUpdateEnabled"] = config.autoUpdateEnabled;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_config_advanced_json, _buffer);
publishString(mqtt_topic_config_advanced_json, _buffer, true);
if(!_preferences->getBool(preference_disable_non_json, false))
{
publishBool(mqtt_topic_config_auto_unlock, config.autoUnLockDisabled == 0);
publishBool(mqtt_topic_config_auto_lock, config.autoLockEnabled == 1);
publishBool(mqtt_topic_config_auto_unlock, config.autoUnLockDisabled == 0, true);
publishBool(mqtt_topic_config_auto_lock, config.autoLockEnabled == 1, true);
}
}
void NetworkLock::publishRssi(const int& rssi)
void NukiNetworkLock::publishRssi(const int& rssi)
{
publishInt(mqtt_topic_lock_rssi, rssi);
publishInt(mqtt_topic_lock_rssi, rssi, true);
}
void NetworkLock::publishRetry(const std::string& message)
void NukiNetworkLock::publishRetry(const std::string& message)
{
publishString(mqtt_topic_lock_retry, message);
publishString(mqtt_topic_lock_retry, message, true);
}
void NetworkLock::publishBleAddress(const std::string &address)
void NukiNetworkLock::publishBleAddress(const std::string &address)
{
publishString(mqtt_topic_lock_address, address);
publishString(mqtt_topic_lock_address, address, true);
}
void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount)
void NukiNetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount)
{
uint index = 0;
char uidString[20];
@@ -956,7 +976,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
jsonEntry["name_ha"] = entry.name;
jsonEntry["index"] = index;
serializeJson(jsonEntry, _buffer, _bufferSize);
publishString(basePath.c_str(), _buffer);
publishString(basePath.c_str(), _buffer, true);
String basePathPrefix = "~";
basePathPrefix.concat(basePath);
@@ -997,7 +1017,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
}
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_keypad_json, _buffer);
publishString(mqtt_topic_keypad_json, _buffer, true);
if(!_preferences->getBool(preference_disable_non_json, false))
{
@@ -1047,7 +1067,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
_network->removeTopic(codeTopic, "createdSec");
_network->removeTopic(codeTopic, "lockCount");
}
for(int j=entries.size(); j<maxKeypadCodeCount; j++)
{
String codesTopic = _mqttPath;
@@ -1062,7 +1082,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
}
}
void NetworkLock::publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry)
void NukiNetworkLock::publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry)
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
@@ -1070,25 +1090,25 @@ void NetworkLock::publishKeypadEntry(const String topic, NukiLock::KeypadEntry e
memset(codeName, 0, sizeof(codeName));
memcpy(codeName, entry.name, sizeof(entry.name));
publishInt(concat(topic, "/id").c_str(), entry.codeId);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
publishString(concat(topic, "/name").c_str(), codeName);
publishInt(concat(topic, "/id").c_str(), entry.codeId, true);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled, true);
publishString(concat(topic, "/name").c_str(), codeName, true);
if(_preferences->getBool(preference_keypad_publish_code, false))
{
publishInt(concat(topic, "/code").c_str(), entry.code);
publishInt(concat(topic, "/code").c_str(), entry.code, true);
}
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);
publishInt(concat(topic, "/createdHour").c_str(), entry.dateCreatedHour);
publishInt(concat(topic, "/createdMin").c_str(), entry.dateCreatedMin);
publishInt(concat(topic, "/createdSec").c_str(), entry.dateCreatedSec);
publishInt(concat(topic, "/lockCount").c_str(), entry.lockCount);
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear, true);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth, true);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay, true);
publishInt(concat(topic, "/createdHour").c_str(), entry.dateCreatedHour, true);
publishInt(concat(topic, "/createdMin").c_str(), entry.dateCreatedMin, true);
publishInt(concat(topic, "/createdSec").c_str(), entry.dateCreatedSec, true);
publishInt(concat(topic, "/lockCount").c_str(), entry.lockCount, true);
}
void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>& timeControlEntries, uint maxTimeControlEntryCount)
void NukiNetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>& timeControlEntries, uint maxTimeControlEntryCount)
{
uint index = 0;
char str[50];
@@ -1166,7 +1186,7 @@ void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>
basePath.concat(std::to_string(index).c_str());
jsonEntry["index"] = index;
serializeJson(jsonEntry, _buffer, _bufferSize);
publishString(basePath.c_str(), _buffer);
publishString(basePath.c_str(), _buffer, true);
String basePathPrefix = "~";
basePathPrefix.concat(basePath);
@@ -1199,13 +1219,13 @@ void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>
{ (char*)"stat_on", (char*)"1" },
{ (char*)"stat_off", (char*)"0" }});
}
++index;
}
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_timecontrol_json, _buffer);
publishString(mqtt_topic_timecontrol_json, _buffer, true);
for(int j=timeControlEntries.size(); j<maxTimeControlEntryCount; j++)
{
String entriesTopic = _mqttPath;
@@ -1217,64 +1237,64 @@ void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>
}
}
void NetworkLock::publishConfigCommandResult(const char* result)
void NukiNetworkLock::publishConfigCommandResult(const char* result)
{
publishString(mqtt_topic_config_action_command_result, result);
publishString(mqtt_topic_config_action_command_result, result, true);
}
void NetworkLock::publishKeypadCommandResult(const char* result)
void NukiNetworkLock::publishKeypadCommandResult(const char* result)
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
publishString(mqtt_topic_keypad_command_result, result);
publishString(mqtt_topic_keypad_command_result, result, true);
}
void NetworkLock::publishKeypadJsonCommandResult(const char* result)
void NukiNetworkLock::publishKeypadJsonCommandResult(const char* result)
{
publishString(mqtt_topic_keypad_json_command_result, result);
publishString(mqtt_topic_keypad_json_command_result, result, true);
}
void NetworkLock::publishTimeControlCommandResult(const char* result)
void NukiNetworkLock::publishTimeControlCommandResult(const char* result)
{
publishString(mqtt_topic_timecontrol_command_result, result);
publishString(mqtt_topic_timecontrol_command_result, result, true);
}
void NetworkLock::publishStatusUpdated(const bool statusUpdated)
void NukiNetworkLock::publishStatusUpdated(const bool statusUpdated)
{
publishBool(mqtt_topic_lock_status_updated, statusUpdated);
}
void NetworkLock::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
void NukiNetworkLock::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
{
_lockActionReceivedCallback = lockActionReceivedCallback;
}
void NetworkLock::setOfficialUpdateReceivedCallback(void (*officialUpdateReceivedCallback)(const char *, const char *))
void NukiNetworkLock::setOfficialUpdateReceivedCallback(void (*officialUpdateReceivedCallback)(const char *, const char *))
{
_officialUpdateReceivedCallback = officialUpdateReceivedCallback;
}
void NetworkLock::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *))
void NukiNetworkLock::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *))
{
_configUpdateReceivedCallback = configUpdateReceivedCallback;
}
void NetworkLock::setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled))
void NukiNetworkLock::setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled))
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
}
void NetworkLock::setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char *))
void NukiNetworkLock::setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char *))
{
_keypadJsonCommandReceivedReceivedCallback = keypadJsonCommandReceivedReceivedCallback;
}
void NetworkLock::setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char *))
void NukiNetworkLock::setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char *))
{
_timeControlCommandReceivedReceivedCallback = timeControlCommandReceivedReceivedCallback;
}
void NetworkLock::buildMqttPath(const char* path, char* outPath, bool offPath)
void NukiNetworkLock::buildMqttPath(const char* path, char* outPath, bool offPath)
{
int offset = 0;
char inPath[181] = {0};
@@ -1301,14 +1321,14 @@ void NetworkLock::buildMqttPath(const char* path, char* outPath, bool offPath)
outPath[i+1] = 0x00;
}
bool NetworkLock::comparePrefixedPath(const char *fullPath, const char *subPath, bool offPath)
bool NukiNetworkLock::comparePrefixedPath(const char *fullPath, const char *subPath, bool offPath)
{
char prefixedPath[500];
buildMqttPath(subPath, prefixedPath, offPath);
return strcmp(fullPath, prefixedPath) == 0;
}
void NetworkLock::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,
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);
@@ -1345,37 +1365,37 @@ void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, cha
}
}
void NetworkLock::removeHASSConfig(char *uidString)
void NukiNetworkLock::removeHASSConfig(char *uidString)
{
_network->removeHASSConfig(uidString);
}
void NetworkLock::publishOffAction(const int value)
void NukiNetworkLock::publishOffAction(const int value)
{
_network->publishInt(_offMqttPath, mqtt_topic_official_lock_action, value, false);
}
void NetworkLock::publishFloat(const char *topic, const float value, const uint8_t precision, bool retain)
void NukiNetworkLock::publishFloat(const char *topic, const float value, const uint8_t precision, bool retain)
{
_network->publishFloat(_mqttPath, topic, value, precision, retain);
}
void NetworkLock::publishInt(const char *topic, const int value, bool retain)
void NukiNetworkLock::publishInt(const char *topic, const int value, bool retain)
{
_network->publishInt(_mqttPath, topic, value, retain);
}
void NetworkLock::publishUInt(const char *topic, const unsigned int value, bool retain)
void NukiNetworkLock::publishUInt(const char *topic, const unsigned int value, bool retain)
{
_network->publishUInt(_mqttPath, topic, value, retain);
}
void NetworkLock::publishBool(const char *topic, const bool value, bool retain)
void NukiNetworkLock::publishBool(const char *topic, const bool value, bool retain)
{
_network->publishBool(_mqttPath, topic, value, retain);
}
bool NetworkLock::publishString(const char *topic, const String &value, bool retain)
bool NukiNetworkLock::publishString(const char *topic, const String &value, bool retain)
{
char str[value.length() + 1];
memset(str, 0, sizeof(str));
@@ -1383,7 +1403,7 @@ bool NetworkLock::publishString(const char *topic, const String &value, bool ret
return publishString(topic, str, retain);
}
bool NetworkLock::publishString(const char *topic, const std::string &value, bool retain)
bool NukiNetworkLock::publishString(const char *topic, const std::string &value, bool retain)
{
char str[value.size() + 1];
memset(str, 0, sizeof(str));
@@ -1391,38 +1411,38 @@ bool NetworkLock::publishString(const char *topic, const std::string &value, boo
return publishString(topic, str, retain);
}
bool NetworkLock::publishString(const char *topic, const char *value, bool retain)
bool NukiNetworkLock::publishString(const char *topic, const char *value, bool retain)
{
return _network->publishString(_mqttPath, topic, value, retain);
}
void NetworkLock::publishULong(const char *topic, const unsigned long value, bool retain)
void NukiNetworkLock::publishULong(const char *topic, const unsigned long value, bool retain)
{
return _network->publishULong(_mqttPath, topic, value, retain);
}
String NetworkLock::concat(String a, String b)
String NukiNetworkLock::concat(String a, String b)
{
String c = a;
c.concat(b);
return c;
}
bool NetworkLock::reconnected()
bool NukiNetworkLock::reconnected()
{
bool r = _reconnected;
_reconnected = false;
return r;
}
uint8_t NetworkLock::queryCommands()
uint8_t NukiNetworkLock::queryCommands()
{
uint8_t qc = _queryCommands;
_queryCommands = 0;
return qc;
}
void NetworkLock::buttonPressActionToString(const NukiLock::ButtonPressAction btnPressAction, char* str) {
void NukiNetworkLock::buttonPressActionToString(const NukiLock::ButtonPressAction btnPressAction, char* str) {
switch (btnPressAction) {
case NukiLock::ButtonPressAction::NoAction:
strcpy(str, "No Action");
@@ -1451,7 +1471,7 @@ void NetworkLock::buttonPressActionToString(const NukiLock::ButtonPressAction bt
}
}
void NetworkLock::homeKitStatusToString(const int hkstatus, char* str) {
void NukiNetworkLock::homeKitStatusToString(const int hkstatus, char* str) {
switch (hkstatus) {
case 0:
strcpy(str, "Not Available");
@@ -1471,7 +1491,7 @@ void NetworkLock::homeKitStatusToString(const int hkstatus, char* str) {
}
}
void NetworkLock::fobActionToString(const int fobact, char* str) {
void NukiNetworkLock::fobActionToString(const int fobact, char* str) {
switch (fobact) {
case 0:
strcpy(str, "No Action");

View File

@@ -8,17 +8,17 @@
#include <list>
#include "NukiConstants.h"
#include "NukiLockConstants.h"
#include "Network.h"
#include "NukiNetwork.h"
#include "QueryCommand.h"
#include "LockActionResult.h"
#define LOCK_LOG_JSON_BUFFER_SIZE 2048
class NetworkLock : public MqttReceiver
class NukiNetworkLock : public MqttReceiver
{
public:
explicit NetworkLock(Network* network, Preferences* preferences, char* buffer, size_t bufferSize);
virtual ~NetworkLock();
explicit NukiNetworkLock(NukiNetwork* network, Preferences* preferences, char* buffer, size_t bufferSize);
virtual ~NukiNetworkLock();
void initialize();
@@ -99,7 +99,7 @@ private:
void buildMqttPath(const char* path, char* outPath, bool offPath = false);
Network* _network;
NukiNetwork* _network;
Preferences* _preferences;
std::vector<char*> _offTopics;

View File

@@ -1,4 +1,4 @@
#include "NetworkOpener.h"
#include "NukiNetworkOpener.h"
#include "Arduino.h"
#include "MqttTopics.h"
#include "PreferencesKeys.h"
@@ -6,7 +6,7 @@
#include "Config.h"
#include <ArduinoJson.h>
NetworkOpener::NetworkOpener(Network* network, Preferences* preferences, char* buffer, size_t bufferSize)
NukiNetworkOpener::NukiNetworkOpener(NukiNetwork* network, Preferences* preferences, char* buffer, size_t bufferSize)
: _preferences(preferences),
_network(network),
_buffer(buffer),
@@ -18,7 +18,7 @@ NetworkOpener::NetworkOpener(Network* network, Preferences* preferences, char* b
_network->registerMqttReceiver(this);
}
void NetworkOpener::initialize()
void NukiNetworkOpener::initialize()
{
String mqttPath = _preferences->getString(preference_mqtt_opener_path);
if(mqttPath.length() > 0)
@@ -120,16 +120,16 @@ void NetworkOpener::initialize()
});
}
void NetworkOpener::update()
void NukiNetworkOpener::update()
{
if(_resetRingStateTs != 0 && millis() >= _resetRingStateTs)
{
_resetRingStateTs = 0;
publishString(mqtt_topic_lock_binary_ring, "standby");
publishString(mqtt_topic_lock_binary_ring, "standby", true);
}
}
void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
void NukiNetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
{
char* value = (char*)payload;
@@ -192,12 +192,12 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
if(strcmp(value, "--") != 0)
{
publishString(mqtt_topic_keypad_command_action, "--");
publishString(mqtt_topic_keypad_command_action, "--", true);
}
publishInt(mqtt_topic_keypad_command_id, _keypadCommandId);
publishString(mqtt_topic_keypad_command_name, _keypadCommandName);
publishString(mqtt_topic_keypad_command_code, _keypadCommandCode);
publishInt(mqtt_topic_keypad_command_enabled, _keypadCommandEnabled);
publishInt(mqtt_topic_keypad_command_id, _keypadCommandId, true);
publishString(mqtt_topic_keypad_command_name, _keypadCommandName, true);
publishString(mqtt_topic_keypad_command_code, _keypadCommandCode, true);
publishInt(mqtt_topic_keypad_command_enabled, _keypadCommandEnabled, true);
}
}
else if(comparePrefixedPath(topic, mqtt_topic_keypad_command_id))
@@ -221,22 +221,22 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
if(comparePrefixedPath(topic, mqtt_topic_query_config) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_CONFIG;
publishString(mqtt_topic_query_config, "0");
publishString(mqtt_topic_query_config, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_lockstate) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_LOCKSTATE;
publishString(mqtt_topic_query_lockstate, "0");
publishString(mqtt_topic_query_lockstate, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_keypad) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_KEYPAD;
publishString(mqtt_topic_query_keypad, "0");
publishString(mqtt_topic_query_keypad, "0", true);
}
else if(comparePrefixedPath(topic, mqtt_topic_query_battery) && strcmp(value, "1") == 0)
{
_queryCommands = _queryCommands | QUERY_COMMAND_BATTERY;
publishString(mqtt_topic_query_battery, "0");
publishString(mqtt_topic_query_battery, "0", true);
}
if(comparePrefixedPath(topic, mqtt_topic_config_action))
@@ -248,7 +248,7 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
_configUpdateReceivedCallback(value);
}
publishString(mqtt_topic_config_action, "--");
publishString(mqtt_topic_config_action, "--", true);
}
if(comparePrefixedPath(topic, mqtt_topic_keypad_json_action))
@@ -260,7 +260,7 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
_keypadJsonCommandReceivedReceivedCallback(value);
}
publishString(mqtt_topic_keypad_json_action, "--");
publishString(mqtt_topic_keypad_json_action, "--", true);
}
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
@@ -272,11 +272,11 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
_timeControlCommandReceivedReceivedCallback(value);
}
publishString(mqtt_topic_timecontrol_action, "--");
publishString(mqtt_topic_timecontrol_action, "--", true);
}
}
void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurnerState, const NukiOpener::OpenerState& lastKeyTurnerState)
void NukiNetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurnerState, const NukiOpener::OpenerState& lastKeyTurnerState)
{
_currentLockState = keyTurnerState.lockState;
@@ -290,7 +290,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
if((_firstTunerStatePublish || keyTurnerState.lockState != lastKeyTurnerState.lockState || keyTurnerState.nukiState != lastKeyTurnerState.nukiState) && keyTurnerState.lockState != NukiOpener::LockState::Undefined)
{
publishString(mqtt_topic_lock_state, str);
publishString(mqtt_topic_lock_state, str, true);
if(_haEnabled)
{
@@ -314,7 +314,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
if(_firstTunerStatePublish || keyTurnerState.trigger != lastKeyTurnerState.trigger)
{
publishString(mqtt_topic_lock_trigger, str);
publishString(mqtt_topic_lock_trigger, str, true);
}
json["trigger"] = str;
@@ -329,7 +329,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
if(_firstTunerStatePublish || keyTurnerState.lastLockAction != lastKeyTurnerState.lastLockAction)
{
publishString(mqtt_topic_lock_last_lock_action, str);
publishString(mqtt_topic_lock_last_lock_action, str, true);
}
json["last_lock_action"] = str;
@@ -343,7 +343,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
if(_firstTunerStatePublish || keyTurnerState.lastLockActionCompletionStatus != lastKeyTurnerState.lastLockActionCompletionStatus)
{
publishString(mqtt_topic_lock_completionStatus, str);
publishString(mqtt_topic_lock_completionStatus, str, true);
}
json["lock_completion_status"] = str;
@@ -353,7 +353,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
if(_firstTunerStatePublish || keyTurnerState.doorSensorState != lastKeyTurnerState.doorSensorState)
{
publishString(mqtt_topic_lock_door_sensor_state, str);
publishString(mqtt_topic_lock_door_sensor_state, str, true);
}
json["door_sensor_state"] = str;
@@ -363,66 +363,66 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
if((_firstTunerStatePublish || keyTurnerState.criticalBatteryState != lastKeyTurnerState.criticalBatteryState) && !_preferences->getBool(preference_disable_non_json, false))
{
publishBool(mqtt_topic_battery_critical, critical);
publishBool(mqtt_topic_battery_critical, critical, true);
}
json["auth_id"] = _authId;
json["auth_name"] = _authName;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_lock_json, _buffer);
publishString(mqtt_topic_lock_json, _buffer, true);
serializeJson(jsonBattery, _buffer, _bufferSize);
publishString(mqtt_topic_battery_basic_json, _buffer);
publishString(mqtt_topic_battery_basic_json, _buffer, true);
_firstTunerStatePublish = false;
}
void NetworkOpener::publishRing(const bool locked)
void NukiNetworkOpener::publishRing(const bool locked)
{
if(locked)
{
publishString(mqtt_topic_lock_ring, "ringlocked");
publishString(mqtt_topic_lock_ring, "ringlocked", true);
}
else
{
publishString(mqtt_topic_lock_ring, "ring");
publishString(mqtt_topic_lock_ring, "ring", true);
}
publishString(mqtt_topic_lock_binary_ring, "ring");
publishString(mqtt_topic_lock_binary_ring, "ring", true);
_resetRingStateTs = millis() + 2000;
}
void NetworkOpener::publishState(NukiOpener::OpenerState lockState)
void NukiNetworkOpener::publishState(NukiOpener::OpenerState lockState)
{
if(lockState.nukiState == NukiOpener::State::ContinuousMode)
{
publishString(mqtt_topic_lock_ha_state, "unlocked");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "unlocked", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
}
else
{
switch (lockState.lockState)
{
case NukiOpener::LockState::Locked:
publishString(mqtt_topic_lock_ha_state, "locked");
publishString(mqtt_topic_lock_binary_state, "locked");
publishString(mqtt_topic_lock_ha_state, "locked", true);
publishString(mqtt_topic_lock_binary_state, "locked", true);
break;
case NukiOpener::LockState::RTOactive:
publishString(mqtt_topic_lock_ha_state, "unlocked");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "unlocked", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiOpener::LockState::Open:
publishString(mqtt_topic_lock_ha_state, "open");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "open", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiOpener::LockState::Opening:
publishString(mqtt_topic_lock_ha_state, "opening");
publishString(mqtt_topic_lock_binary_state, "unlocked");
publishString(mqtt_topic_lock_ha_state, "opening", true);
publishString(mqtt_topic_lock_binary_state, "unlocked", true);
break;
case NukiOpener::LockState::Undefined:
case NukiOpener::LockState::Uncalibrated:
publishString(mqtt_topic_lock_ha_state, "jammed");
publishString(mqtt_topic_lock_ha_state, "jammed", true);
break;
default:
break;
@@ -430,7 +430,7 @@ void NetworkOpener::publishState(NukiOpener::OpenerState lockState)
}
}
void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntry>& logEntries, bool latest)
void NukiNetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntry>& logEntries, bool latest)
{
char str[50];
char authName[33];
@@ -581,45 +581,45 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
{
_lastRollingLog = log.index;
serializeJson(entry, _buffer, _bufferSize);
publishString(mqtt_topic_lock_log_rolling, _buffer);
publishInt(mqtt_topic_lock_log_rolling_last, log.index);
publishString(mqtt_topic_lock_log_rolling, _buffer, true);
publishInt(mqtt_topic_lock_log_rolling_last, log.index, true);
}
}
serializeJson(json, _buffer, _bufferSize);
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer);
else publishString(mqtt_topic_lock_log, _buffer);
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer, true);
else publishString(mqtt_topic_lock_log, _buffer, true);
if(authIndex > 0)
{
publishUInt(mqtt_topic_lock_auth_id, _authId);
publishString(mqtt_topic_lock_auth_name, _authName);
publishUInt(mqtt_topic_lock_auth_id, _authId, true);
publishString(mqtt_topic_lock_auth_name, _authName, true);
}
}
void NetworkOpener::clearAuthorizationInfo()
void NukiNetworkOpener::clearAuthorizationInfo()
{
publishString(mqtt_topic_lock_log, "--");
publishUInt(mqtt_topic_lock_auth_id, 0);
publishString(mqtt_topic_lock_auth_name, "--");
publishString(mqtt_topic_lock_log, "--", true);
publishUInt(mqtt_topic_lock_auth_id, 0, true);
publishString(mqtt_topic_lock_auth_name, "--", true);
}
void NetworkOpener::publishCommandResult(const char *resultStr)
void NukiNetworkOpener::publishCommandResult(const char *resultStr)
{
publishString(mqtt_topic_lock_action_command_result, resultStr);
publishString(mqtt_topic_lock_action_command_result, resultStr, true);
}
void NetworkOpener::publishLockstateCommandResult(const char *resultStr)
void NukiNetworkOpener::publishLockstateCommandResult(const char *resultStr)
{
publishString(mqtt_topic_query_lockstate_command_result, resultStr);
publishString(mqtt_topic_query_lockstate_command_result, resultStr, true);
}
void NetworkOpener::publishBatteryReport(const NukiOpener::BatteryReport& batteryReport)
void NukiNetworkOpener::publishBatteryReport(const NukiOpener::BatteryReport& batteryReport)
{
if(!_preferences->getBool(preference_disable_non_json, false))
{
publishFloat(mqtt_topic_battery_voltage, (float)batteryReport.batteryVoltage / 1000.0);
publishFloat(mqtt_topic_battery_voltage, (float)batteryReport.batteryVoltage / 1000.0, true);
}
char str[50];
@@ -635,10 +635,10 @@ void NetworkOpener::publishBatteryReport(const NukiOpener::BatteryReport& batter
json["lowestVoltage"] = (float)batteryReport.lowestVoltage / 1000.0;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_battery_advanced_json, _buffer);
publishString(mqtt_topic_battery_advanced_json, _buffer, true);
}
void NetworkOpener::publishConfig(const NukiOpener::Config &config)
void NukiNetworkOpener::publishConfig(const NukiOpener::Config &config)
{
char str[50];
char curTime[20];
@@ -689,19 +689,19 @@ void NetworkOpener::publishConfig(const NukiOpener::Config &config)
json["timeZone"] = str;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_config_basic_json, _buffer);
publishString(mqtt_topic_config_basic_json, _buffer, true);
if(!_preferences->getBool(preference_disable_non_json, false))
{
publishBool(mqtt_topic_config_button_enabled, config.buttonEnabled == 1);
publishBool(mqtt_topic_config_led_enabled, config.ledFlashEnabled == 1);
publishBool(mqtt_topic_config_button_enabled, config.buttonEnabled == 1, true);
publishBool(mqtt_topic_config_led_enabled, config.ledFlashEnabled == 1, true);
}
publishString(mqtt_topic_info_firmware_version, std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]));
publishString(mqtt_topic_info_hardware_version, std::to_string(config.hardwareRevision[0]) + "." + std::to_string(config.hardwareRevision[1]));
publishString(mqtt_topic_info_firmware_version, std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]), true);
publishString(mqtt_topic_info_hardware_version, std::to_string(config.hardwareRevision[0]) + "." + std::to_string(config.hardwareRevision[1]), true);
}
void NetworkOpener::publishAdvancedConfig(const NukiOpener::AdvancedConfig &config)
void NukiNetworkOpener::publishAdvancedConfig(const NukiOpener::AdvancedConfig &config)
{
char str[50];
@@ -745,30 +745,30 @@ void NetworkOpener::publishAdvancedConfig(const NukiOpener::AdvancedConfig &conf
json["automaticBatteryTypeDetection"] = config.automaticBatteryTypeDetection;
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_config_advanced_json, _buffer);
publishString(mqtt_topic_config_advanced_json, _buffer, true);
if(!_preferences->getBool(preference_disable_non_json, false))
{
publishUInt(mqtt_topic_config_sound_level, config.soundLevel);
publishUInt(mqtt_topic_config_sound_level, config.soundLevel, true);
}
}
void NetworkOpener::publishRssi(const int &rssi)
void NukiNetworkOpener::publishRssi(const int &rssi)
{
publishInt(mqtt_topic_lock_rssi, rssi);
publishInt(mqtt_topic_lock_rssi, rssi, true);
}
void NetworkOpener::publishRetry(const std::string& message)
void NukiNetworkOpener::publishRetry(const std::string& message)
{
publishString(mqtt_topic_lock_retry, message);
publishString(mqtt_topic_lock_retry, message, true);
}
void NetworkOpener::publishBleAddress(const std::string &address)
void NukiNetworkOpener::publishBleAddress(const std::string &address)
{
publishString(mqtt_topic_lock_address, address);
publishString(mqtt_topic_lock_address, address, true);
}
void NetworkOpener::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)
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");
availabilityTopic.concat("/maintenance/mqttConnectionState");
@@ -795,12 +795,12 @@ void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, c
}
}
void NetworkOpener::removeHASSConfig(char* uidString)
void NukiNetworkOpener::removeHASSConfig(char* uidString)
{
_network->removeHASSConfig(uidString);
}
void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount)
void NukiNetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount)
{
uint index = 0;
char uidString[20];
@@ -904,7 +904,7 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
jsonEntry["name_ha"] = entry.name;
jsonEntry["index"] = index;
serializeJson(jsonEntry, _buffer, _bufferSize);
publishString(basePath.c_str(), _buffer);
publishString(basePath.c_str(), _buffer, true);
String basePathPrefix = "~";
basePathPrefix.concat(basePath);
@@ -945,7 +945,7 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
}
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_keypad_json, _buffer);
publishString(mqtt_topic_keypad_json, _buffer, true);
if(!_preferences->getBool(preference_disable_non_json, false))
{
@@ -1008,7 +1008,7 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
}
}
void NetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEntry>& timeControlEntries, uint maxTimeControlEntryCount)
void NukiNetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEntry>& timeControlEntries, uint maxTimeControlEntryCount)
{
uint index = 0;
char str[50];
@@ -1086,7 +1086,7 @@ void NetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEn
basePath.concat(std::to_string(index).c_str());
jsonEntry["index"] = index;
serializeJson(jsonEntry, _buffer, _bufferSize);
publishString(basePath.c_str(), _buffer);
publishString(basePath.c_str(), _buffer, true);
String basePathPrefix = "~";
basePathPrefix.concat(basePath);
@@ -1123,7 +1123,7 @@ void NetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEn
}
serializeJson(json, _buffer, _bufferSize);
publishString(mqtt_topic_timecontrol_json, _buffer);
publishString(mqtt_topic_timecontrol_json, _buffer, true);
for(int j=timeControlEntries.size(); j<maxTimeControlEntryCount; j++)
{
@@ -1136,79 +1136,79 @@ void NetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEn
}
}
void NetworkOpener::publishConfigCommandResult(const char* result)
void NukiNetworkOpener::publishConfigCommandResult(const char* result)
{
publishString(mqtt_topic_config_action_command_result, result);
publishString(mqtt_topic_config_action_command_result, result, true);
}
void NetworkOpener::publishKeypadCommandResult(const char* result)
void NukiNetworkOpener::publishKeypadCommandResult(const char* result)
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
publishString(mqtt_topic_keypad_command_result, result);
publishString(mqtt_topic_keypad_command_result, result, true);
}
void NetworkOpener::publishKeypadJsonCommandResult(const char* result)
void NukiNetworkOpener::publishKeypadJsonCommandResult(const char* result)
{
publishString(mqtt_topic_keypad_json_command_result, result);
publishString(mqtt_topic_keypad_json_command_result, result, true);
}
void NetworkOpener::publishTimeControlCommandResult(const char* result)
void NukiNetworkOpener::publishTimeControlCommandResult(const char* result)
{
publishString(mqtt_topic_timecontrol_command_result, result);
publishString(mqtt_topic_timecontrol_command_result, result, true);
}
void NetworkOpener::publishStatusUpdated(const bool statusUpdated)
void NukiNetworkOpener::publishStatusUpdated(const bool statusUpdated)
{
publishBool(mqtt_topic_lock_status_updated, statusUpdated);
}
void NetworkOpener::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
void NukiNetworkOpener::setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char *))
{
_lockActionReceivedCallback = lockActionReceivedCallback;
}
void NetworkOpener::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *))
void NukiNetworkOpener::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *))
{
_configUpdateReceivedCallback = configUpdateReceivedCallback;
}
void NetworkOpener::setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled))
void NukiNetworkOpener::setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled))
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
_keypadCommandReceivedReceivedCallback = keypadCommandReceivedReceivedCallback;
}
void NetworkOpener::setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char *))
void NukiNetworkOpener::setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char *))
{
_keypadJsonCommandReceivedReceivedCallback = keypadJsonCommandReceivedReceivedCallback;
}
void NetworkOpener::setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char *))
void NukiNetworkOpener::setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char *))
{
_timeControlCommandReceivedReceivedCallback = timeControlCommandReceivedReceivedCallback;
}
void NetworkOpener::publishFloat(const char *topic, const float value, const uint8_t precision, bool retain)
void NukiNetworkOpener::publishFloat(const char *topic, const float value, const uint8_t precision, bool retain)
{
_network->publishFloat(_mqttPath, topic, value, precision, retain);
}
void NetworkOpener::publishInt(const char *topic, const int value, bool retain)
void NukiNetworkOpener::publishInt(const char *topic, const int value, bool retain)
{
_network->publishInt(_mqttPath, topic, value, retain);
}
void NetworkOpener::publishUInt(const char *topic, const unsigned int value, bool retain)
void NukiNetworkOpener::publishUInt(const char *topic, const unsigned int value, bool retain)
{
_network->publishUInt(_mqttPath, topic, value, retain);
}
void NetworkOpener::publishBool(const char *topic, const bool value, bool retain)
void NukiNetworkOpener::publishBool(const char *topic, const bool value, bool retain)
{
_network->publishBool(_mqttPath, topic, value, retain);
}
void NetworkOpener::publishString(const char *topic, const String &value, bool retain)
void NukiNetworkOpener::publishString(const char *topic, const String &value, bool retain)
{
char str[value.length() + 1];
memset(str, 0, sizeof(str));
@@ -1216,7 +1216,7 @@ void NetworkOpener::publishString(const char *topic, const String &value, bool r
publishString(topic, str, retain);
}
void NetworkOpener::publishString(const char *topic, const std::string &value, bool retain)
void NukiNetworkOpener::publishString(const char *topic, const std::string &value, bool retain)
{
char str[value.size() + 1];
memset(str, 0, sizeof(str));
@@ -1224,12 +1224,12 @@ void NetworkOpener::publishString(const char *topic, const std::string &value, b
publishString(topic, str, retain);
}
void NetworkOpener::publishString(const char* topic, const char* value, bool retain)
void NukiNetworkOpener::publishString(const char* topic, const char* value, bool retain)
{
_network->publishString(_mqttPath, topic, value, retain);
}
void NetworkOpener::publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry)
void NukiNetworkOpener::publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry)
{
if(_preferences->getBool(preference_disable_non_json, false)) return;
@@ -1237,25 +1237,25 @@ void NetworkOpener::publishKeypadEntry(const String topic, NukiLock::KeypadEntry
memset(codeName, 0, sizeof(codeName));
memcpy(codeName, entry.name, sizeof(entry.name));
publishInt(concat(topic, "/id").c_str(), entry.codeId);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
publishString(concat(topic, "/name").c_str(), codeName);
publishInt(concat(topic, "/id").c_str(), entry.codeId, true);
publishBool(concat(topic, "/enabled").c_str(), entry.enabled, true);
publishString(concat(topic, "/name").c_str(), codeName, true);
if(_preferences->getBool(preference_keypad_publish_code, false))
{
publishInt(concat(topic, "/code").c_str(), entry.code);
publishInt(concat(topic, "/code").c_str(), entry.code, true);
}
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);
publishInt(concat(topic, "/createdHour").c_str(), entry.dateCreatedHour);
publishInt(concat(topic, "/createdMin").c_str(), entry.dateCreatedMin);
publishInt(concat(topic, "/createdSec").c_str(), entry.dateCreatedSec);
publishInt(concat(topic, "/lockCount").c_str(), entry.lockCount);
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear, true);
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth, true);
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay, true);
publishInt(concat(topic, "/createdHour").c_str(), entry.dateCreatedHour, true);
publishInt(concat(topic, "/createdMin").c_str(), entry.dateCreatedMin, true);
publishInt(concat(topic, "/createdSec").c_str(), entry.dateCreatedSec, true);
publishInt(concat(topic, "/lockCount").c_str(), entry.lockCount, true);
}
void NetworkOpener::buildMqttPath(const char* path, char* outPath)
void NukiNetworkOpener::buildMqttPath(const char* path, char* outPath)
{
int offset = 0;
for(const char& c : _mqttPath)
@@ -1277,14 +1277,14 @@ void NetworkOpener::buildMqttPath(const char* path, char* outPath)
outPath[offset] = 0x00;
}
void NetworkOpener::subscribe(const char *path)
void NukiNetworkOpener::subscribe(const char *path)
{
char prefixedPath[500];
buildMqttPath(path, prefixedPath);
_network->subscribe(prefixedPath, MQTT_QOS_LEVEL);
}
bool NetworkOpener::comparePrefixedPath(const char *fullPath, const char *subPath)
bool NukiNetworkOpener::comparePrefixedPath(const char *fullPath, const char *subPath)
{
char prefixedPath[500];
buildMqttPath(subPath, prefixedPath);
@@ -1292,28 +1292,28 @@ bool NetworkOpener::comparePrefixedPath(const char *fullPath, const char *subPat
return strcmp(fullPath, prefixedPath) == 0;
}
String NetworkOpener::concat(String a, String b)
String NukiNetworkOpener::concat(String a, String b)
{
String c = a;
c.concat(b);
return c;
}
bool NetworkOpener::reconnected()
bool NukiNetworkOpener::reconnected()
{
bool r = _reconnected;
_reconnected = false;
return r;
}
uint8_t NetworkOpener::queryCommands()
uint8_t NukiNetworkOpener::queryCommands()
{
uint8_t qc = _queryCommands;
_queryCommands = 0;
return qc;
}
void NetworkOpener::buttonPressActionToString(const NukiOpener::ButtonPressAction btnPressAction, char* str) {
void NukiNetworkOpener::buttonPressActionToString(const NukiOpener::ButtonPressAction btnPressAction, char* str) {
switch (btnPressAction) {
case NukiOpener::ButtonPressAction::NoAction:
strcpy(str, "No Action");
@@ -1345,7 +1345,7 @@ void NetworkOpener::buttonPressActionToString(const NukiOpener::ButtonPressActio
}
}
void NetworkOpener::fobActionToString(const int fobact, char* str) {
void NukiNetworkOpener::fobActionToString(const int fobact, char* str) {
switch (fobact) {
case 0:
strcpy(str, "No Action");
@@ -1371,7 +1371,7 @@ void NetworkOpener::fobActionToString(const int fobact, char* str) {
}
}
void NetworkOpener::capabilitiesToString(const int capabilities, char* str) {
void NukiNetworkOpener::capabilitiesToString(const int capabilities, char* str) {
switch (capabilities) {
case 0:
strcpy(str, "Door opener");
@@ -1388,7 +1388,7 @@ void NetworkOpener::capabilitiesToString(const int capabilities, char* str) {
}
}
void NetworkOpener::operatingModeToString(const int opmode, char* str) {
void NukiNetworkOpener::operatingModeToString(const int opmode, char* str) {
switch (opmode) {
case 0:
strcpy(str, "Generic door opener");
@@ -1444,7 +1444,7 @@ void NetworkOpener::operatingModeToString(const int opmode, char* str) {
}
}
void NetworkOpener::doorbellSuppressionToString(const int dbsupr, char* str) {
void NukiNetworkOpener::doorbellSuppressionToString(const int dbsupr, char* str) {
switch (dbsupr) {
case 0:
strcpy(str, "Off");
@@ -1476,7 +1476,7 @@ void NetworkOpener::doorbellSuppressionToString(const int dbsupr, char* str) {
}
}
void NetworkOpener::soundToString(const int sound, char* str) {
void NukiNetworkOpener::soundToString(const int sound, char* str) {
switch (sound) {
case 0:
strcpy(str, "No Sound");

View File

@@ -7,13 +7,13 @@
#include <vector>
#include "NukiConstants.h"
#include "NukiOpenerConstants.h"
#include "NetworkLock.h"
#include "NukiNetworkLock.h"
class NetworkOpener : public MqttReceiver
class NukiNetworkOpener : public MqttReceiver
{
public:
explicit NetworkOpener(Network* network, Preferences* preferences, char* buffer, size_t bufferSize);
virtual ~NetworkOpener() = default;
explicit NukiNetworkOpener(NukiNetwork* network, Preferences* preferences, char* buffer, size_t bufferSize);
virtual ~NukiNetworkOpener() = default;
void initialize();
void update();
@@ -77,7 +77,7 @@ private:
Preferences* _preferences;
Network* _network = nullptr;
NukiNetwork* _network = nullptr;
char _mqttPath[181] = {0};
bool _isConnected = false;

View File

@@ -10,7 +10,7 @@
NukiOpenerWrapper* nukiOpenerInst;
Preferences* nukiOpenerPreferences = nullptr;
NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NetworkOpener* network, Gpio* gpio, Preferences* preferences)
NukiOpenerWrapper::NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkOpener* network, Gpio* gpio, Preferences* preferences)
: _deviceName(deviceName),
_deviceId(deviceId),
_nukiOpener(deviceName, _deviceId->get()),
@@ -103,6 +103,7 @@ void NukiOpenerWrapper::initialize()
}
_nukiOpener.setEventHandler(this);
_nukiOpener.setDisonnectTimeout(5000);
Log->print(F("Lock state interval: "));
Log->print(_intervalLockstate);
@@ -220,17 +221,8 @@ void NukiOpenerWrapper::update()
if(_nextLockAction != (NukiOpener::LockAction)0xff && ts > _nextRetryTs)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Nuki::CmdResult cmdResult = _nukiOpener.lockAction(_nextLockAction, 0, 0);
_taskRunning = false;
delay(250);
char resultStr[15] = {0};
NukiOpener::cmdResultToString(cmdResult, resultStr);
@@ -350,28 +342,18 @@ void NukiOpenerWrapper::unpair()
void NukiOpenerWrapper::updateKeyTurnerState()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying opener state: "));
result =_nukiOpener.requestOpenerState(&_keyTurnerState);
_taskRunning = false;
if(!_nukiConfigValid) {
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
char resultStr[15];
@@ -383,7 +365,7 @@ void NukiOpenerWrapper::updateKeyTurnerState()
{
_retryLockstateCount++;
postponeBleWatchdog();
if(_retryLockstateCount < _nrOfRetries)
if(_retryLockstateCount < _nrOfRetries + 1)
{
_nextLockStateUpdateTs = millis() + _retryDelay;
}
@@ -435,28 +417,18 @@ void NukiOpenerWrapper::updateKeyTurnerState()
void NukiOpenerWrapper::updateBatteryState()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying opener battery state: "));
result = _nukiOpener.requestBatteryReport(&_batteryReport);
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
printCommandResult(result);
@@ -495,27 +467,17 @@ void NukiOpenerWrapper::updateConfig()
const int pinStatus = _preferences->getInt(preference_opener_pin_status, 4);
if(isPinSet()) {
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
result = _nukiOpener.verifySecurityPin();
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if(result != Nuki::CmdResult::Success)
@@ -577,28 +539,18 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
if(!retrieved)
{
delay(250);
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Retrieve log entries: "));
result = _nukiOpener.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
Log->println(result);
@@ -654,28 +606,18 @@ void NukiOpenerWrapper::updateKeypad(bool retrieved)
if(!retrieved)
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying opener keypad: "));
result = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
printCommandResult(result);
@@ -725,28 +667,18 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
if(!retrieved)
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying opener time control: "));
result = _nukiOpener.retrieveTimeControlEntries();
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
printCommandResult(result);
@@ -1045,14 +977,6 @@ void NukiOpenerWrapper::onConfigUpdateReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(basicKeys[i], "name") == 0)
{
if(strlen(jsonchar) <= 32)
@@ -1210,8 +1134,6 @@ void NukiOpenerWrapper::onConfigUpdateReceived(const char *value)
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if(cmdResult == Nuki::CmdResult::Success) basicUpdated = true;
@@ -1245,14 +1167,6 @@ void NukiOpenerWrapper::onConfigUpdateReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(advancedKeys[j], "intercomID") == 0)
{
const uint16_t keyvalue = atoi(jsonchar);
@@ -1478,8 +1392,6 @@ void NukiOpenerWrapper::onConfigUpdateReceived(const char *value)
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if(cmdResult == Nuki::CmdResult::Success) advancedUpdated = true;
@@ -1573,14 +1485,6 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(command, "add") == 0)
{
if(name == "" || name == "--")
@@ -1604,10 +1508,10 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
size_t nameLen = name.length();
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
_taskRunning = true;
result = _nukiOpener.addKeypadEntry(entry);
_taskRunning = false;
Log->print("Add keypad code: "); Log->println((int)result);
delay(250);
Log->print("Add keypad code: ");
Log->println((int)result);
updateKeypad(false);
}
else if(strcmp(command, "delete") == 0)
@@ -1618,10 +1522,10 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
return;
}
_taskRunning = true;
result = _nukiOpener.deleteKeypadEntry(id);
_taskRunning = false;
Log->print("Delete keypad code: "); Log->println((int)result);
delay(250);
Log->print("Delete keypad code: ");
Log->println((int)result);
updateKeypad(false);
}
else if(strcmp(command, "update") == 0)
@@ -1654,13 +1558,13 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
entry.enabled = enabled == 0 ? 0 : 1;
_taskRunning = true;
result = _nukiOpener.updateKeypadEntry(entry);
_taskRunning = false;
Log->print("Update keypad code: "); Log->println((int)result);
delay(250);
Log->print("Update keypad code: ");
Log->println((int)result);
updateKeypad(false);
}
else if(command == "--")
else if(strcmp(command, "--") == 0)
{
return;
}
@@ -1674,8 +1578,6 @@ void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if((int)result != -1)
@@ -1771,20 +1673,11 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(action, "delete") == 0) {
if(idExists)
{
_taskRunning = true;
result = _nukiOpener.deleteKeypadEntry(codeId);
_taskRunning = false;
delay(250);
Log->print(F("Delete keypad code: "));
Log->println((int)result);
}
@@ -1970,9 +1863,8 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
entry.allowedUntilTimeMin = allowedUntilTimeAr[1];
}
_taskRunning = true;
result = _nukiOpener.addKeypadEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Add keypad code: "));
Log->println((int)result);
}
@@ -1990,17 +1882,8 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
return;
}
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Nuki::CmdResult resultKp = _nukiOpener.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
_taskRunning = false;
delay(250);
bool foundExisting = false;
if(resultKp == Nuki::CmdResult::Success)
@@ -2075,7 +1958,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
entry.codeId = codeId;
entry.code = code;
if(name.length() < 1)
if(!name.length() > 0)
{
size_t nameLen = strlen(oldName);
memcpy(&entry.name, oldName, nameLen > 20 ? 20 : nameLen);
@@ -2128,9 +2011,8 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
}
}
_taskRunning = true;
result = _nukiOpener.updateKeypadEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Update keypad code: "));
Log->println((int)result);
}
@@ -2145,8 +2027,6 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
updateKeypad(false);
@@ -2235,20 +2115,11 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(action, "delete") == 0) {
if(idExists)
{
_taskRunning = true;
result = _nukiOpener.removeTimeControlEntry(entryId);
_taskRunning = false;
delay(250);
Log->print(F("Delete time control: "));
Log->println((int)result);
}
@@ -2306,10 +2177,8 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
}
entry.lockAction = timeControlLockAction;
_taskRunning = true;
result = _nukiOpener.addTimeControlEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Add time control: "));
Log->println((int)result);
}
@@ -2321,17 +2190,8 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
return;
}
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Nuki::CmdResult resultTc = _nukiOpener.retrieveTimeControlEntries();
_taskRunning = false;
delay(250);
bool foundExisting = false;
if(resultTc == Nuki::CmdResult::Success)
@@ -2380,10 +2240,8 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
}
entry.lockAction = timeControlLockAction;
_taskRunning = true;
result = _nukiOpener.updateTimeControlEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Update time control: "));
Log->println((int)result);
}
@@ -2398,8 +2256,6 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if((int)result != -1)
@@ -2448,6 +2304,7 @@ void NukiOpenerWrapper::notify(Nuki::EventType eventType)
{
if(eventType == Nuki::EventType::KeyTurnerStatusUpdated)
{
Log->println("KeyTurnerStatusUpdated");
_statusUpdated = true;
_network->publishStatusUpdated(_statusUpdated);
}
@@ -2455,30 +2312,19 @@ void NukiOpenerWrapper::notify(Nuki::EventType eventType)
void NukiOpenerWrapper::readConfig()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Reading opener config. Result: "));
Nuki::CmdResult result = _nukiOpener.requestConfig(&_nukiConfig);
_taskRunning = false;
delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
char resultStr[20];
@@ -2489,29 +2335,19 @@ void NukiOpenerWrapper::readConfig()
void NukiOpenerWrapper::readAdvancedConfig()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
result = _nukiOpener.requestAdvancedConfig(&_nukiAdvancedConfig);
_taskRunning = false;
delay(250);
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiAdvancedConfigValid) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
char resultStr[20];
@@ -2541,29 +2377,19 @@ void NukiOpenerWrapper::disableHASS()
{
if(!_nukiConfigValid) // only ask for config once to save battery life
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
result = _nukiOpener.requestConfig(&_nukiConfig);
_taskRunning = false;
delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include "NukiOpener.h"
#include "NetworkOpener.h"
#include "NukiNetworkOpener.h"
#include "NukiOpenerConstants.h"
#include "NukiDataTypes.h"
#include "BleScanner.h"
@@ -11,7 +11,7 @@
class NukiOpenerWrapper : public NukiOpener::SmartlockEventHandler
{
public:
NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NetworkOpener* network, Gpio* gpio, Preferences* preferences);
NukiOpenerWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkOpener* network, Gpio* gpio, Preferences* preferences);
virtual ~NukiOpenerWrapper();
void initialize();
@@ -90,7 +90,7 @@ private:
NukiDeviceId* _deviceId = nullptr;
NukiOpener::NukiOpener _nukiOpener;
BleScanner::Scanner* _bleScanner = nullptr;
NetworkOpener* _network = nullptr;
NukiNetworkOpener* _network = nullptr;
Gpio* _gpio = nullptr;
Preferences* _preferences = nullptr;
int _intervalLockstate = 0; // seconds
@@ -100,7 +100,6 @@ private:
int _restartBeaconTimeout = 0; // seconds
bool _publishAuthData = false;
bool _clearAuthData = false;
bool _taskRunning = false;
int _nrOfRetries = 0;
int _retryDelay = 0;
int _retryCount = 0;

View File

@@ -8,10 +8,10 @@
#include "Config.h"
NukiWrapper* nukiInst;
NetworkLock* networkInst;
NukiNetworkLock* networkInst;
Preferences* nukiLockPreferences = nullptr;
NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NetworkLock* network, Gpio* gpio, Preferences* preferences)
NukiWrapper::NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, Gpio* gpio, Preferences* preferences)
: _deviceName(deviceName),
_deviceId(deviceId),
_bleScanner(scanner),
@@ -72,65 +72,106 @@ 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);
_preferences->putBool(preference_check_updates, true);
_preferences->putBool(preference_opener_continuous_mode, false);
_preferences->putBool(preference_network_wifi_fallback_disabled, false);
_preferences->putBool(preference_official_hybrid, false);
_preferences->putBool(preference_official_hybrid_actions, false);
_preferences->putBool(preference_official_hybrid_retry, false);
_preferences->putBool(preference_disable_non_json, false);
_preferences->putBool(preference_update_from_mqtt, false);
_preferences->putBool(preference_ip_dhcp_enabled, true);
_preferences->putBool(preference_enable_bootloop_reset, false);
_preferences->putBool(preference_show_secrets, false);
_preferences->putBool(preference_conf_info_enabled, true);
_preferences->putBool(preference_keypad_info_enabled, false);
_preferences->putBool(preference_keypad_topic_per_entry, false);
_preferences->putBool(preference_keypad_publish_code, false);
_preferences->putBool(preference_keypad_control_enabled, false);
_preferences->putBool(preference_timecontrol_info_enabled, false);
_preferences->putBool(preference_timecontrol_topic_per_entry, false);
_preferences->putBool(preference_timecontrol_control_enabled, false);
_preferences->putBool(preference_publish_authdata, false);
_preferences->putBool(preference_register_as_app, false);
_preferences->putBool(preference_register_opener_as_app, false);
_preferences->putInt(preference_mqtt_broker_port, 1883);
_preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
_preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
_preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
_preferences->putInt(preference_authlog_max_entries, MAX_AUTHLOG);
_preferences->putInt(preference_keypad_max_entries, MAX_KEYPAD);
_preferences->putInt(preference_timecontrol_max_entries, MAX_TIMECONTROL);
_preferences->putInt(preference_query_interval_hybrid_lockstate, 600);
_preferences->putInt(preference_rssi_publish_interval, 60);
_preferences->putInt(preference_network_timeout, 60);
_preferences->putInt(preference_command_nr_of_retries, 3);
_preferences->putInt(preference_command_retry_delay, 1000);
_preferences->putInt(preference_restart_ble_beacon_lost, 60);
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
_preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
uint32_t basicLockConfigAclPrefs[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
_preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
uint32_t basicOpenerConfigAclPrefs[14] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
_preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
uint32_t advancedLockConfigAclPrefs[22] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
_preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
uint32_t advancedOpenerConfigAclPrefs[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
_preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
_preferences->putInt(preference_query_interval_lockstate, 1800);
_preferences->putInt(preference_query_interval_configuration, 3600);
_preferences->putInt(preference_query_interval_battery, 1800);
_preferences->putInt(preference_query_interval_keypad, 1800);
_preferences->putInt(preference_presence_detection_timeout, -1);
}
if(_nrOfRetries < 0 || _nrOfRetries == 200)
{
Log->println("Invalid nrOfRetries, revert to default (3)");
_nrOfRetries = 3;
_preferences->putInt(preference_command_nr_of_retries, _nrOfRetries);
}
if(_retryDelay <= 100)
{
Log->println("Invalid retryDelay, revert to default (100)");
_retryDelay = 100;
_preferences->putInt(preference_command_retry_delay, _retryDelay);
}
if(_intervalLockstate == 0)
{
Log->println("Invalid intervalLockstate, revert to default (1800)");
_intervalLockstate = 60 * 30;
_preferences->putInt(preference_query_interval_lockstate, _intervalLockstate);
}
if(_intervalHybridLockstate == 0)
{
Log->println("Invalid intervalHybridLockstate, revert to default (600)");
_intervalHybridLockstate = 60 * 10;
_preferences->putInt(preference_query_interval_hybrid_lockstate, _intervalHybridLockstate);
}
if(_intervalConfig == 0)
{
Log->println("Invalid intervalConfig, revert to default (3600)");
_intervalConfig = 60 * 60;
_preferences->putInt(preference_query_interval_configuration, _intervalConfig);
}
if(_intervalBattery == 0)
{
Log->println("Invalid intervalBattery, revert to default (1800)");
_intervalBattery = 60 * 30;
_preferences->putInt(preference_query_interval_battery, _intervalBattery);
}
if(_intervalKeypad == 0)
{
Log->println("Invalid intervalKeypad, revert to default (1800)");
_intervalKeypad = 60 * 30;
_preferences->putInt(preference_query_interval_keypad, _intervalKeypad);
}
if(_restartBeaconTimeout < 10)
{
Log->println("Invalid restartBeaconTimeout, revert to default (-1)");
_restartBeaconTimeout = -1;
_preferences->putInt(preference_restart_ble_beacon_lost, _restartBeaconTimeout);
}
_nukiLock.setEventHandler(this);
_nukiLock.setDisonnectTimeout(5000);
Log->print(F("Lock state interval: "));
Log->print(_intervalLockstate);
@@ -150,6 +191,7 @@ void NukiWrapper::update()
if(!_paired)
{
Log->println(F("Nuki lock start pairing"));
_preferences->getBool(preference_register_as_app) ? Log->println(F("Pairing as app")) : Log->println(F("Pairing as bridge"));
_network->publishBleAddress("");
Nuki::AuthorizationIdType idType = _preferences->getBool(preference_register_as_app) ?
@@ -190,6 +232,7 @@ void NukiWrapper::update()
if(_statusUpdated || _nextLockStateUpdateTs == 0 || ts >= _nextLockStateUpdateTs || (queryCommands & QUERY_COMMAND_LOCKSTATE) > 0)
{
Log->println("Updating Lock state based on timer or query");
_statusUpdated = false;
_nextLockStateUpdateTs = ts + _intervalLockstate * 1000;
updateKeyTurnerState();
@@ -202,11 +245,13 @@ void NukiWrapper::update()
}
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(_hassEnabled && !_hassSetupCompleted)
@@ -247,23 +292,14 @@ void NukiWrapper::update()
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(_nextLockAction != (NukiLock::LockAction)0xff && ts > _nextRetryTs)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Nuki::CmdResult cmdResult = _nukiLock.lockAction(_nextLockAction, 0, 0);
_taskRunning = false;
char resultStr[15] = {0};
NukiLock::cmdResultToString(cmdResult, resultStr);
@@ -315,6 +351,7 @@ void NukiWrapper::update()
if(_clearAuthData)
{
Log->println("Clearing Lock auth data");
_network->clearAuthorizationInfo();
_clearAuthData = false;
}
@@ -376,28 +413,23 @@ void NukiWrapper::unpair()
void NukiWrapper::updateKeyTurnerState()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
Log->println("Querying lock state");
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying lock state: "));
Log->print(F("Result (attempt "));
Log->print(_retryCount + 1);
Log->print("): ");
result =_nukiLock.requestKeyTurnerState(&_keyTurnerState);
_taskRunning = false;
if(!_nukiConfigValid) {
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
char resultStr[15];
@@ -407,10 +439,14 @@ void NukiWrapper::updateKeyTurnerState()
if(result != Nuki::CmdResult::Success)
{
Log->println("Query lock state failed");
_retryLockstateCount++;
postponeBleWatchdog();
if(_retryLockstateCount < _nrOfRetries)
if(_retryLockstateCount < _nrOfRetries + 1)
{
Log->print(F("Query lock state retrying in "));
Log->print(_retryDelay);
Log->println("ms");
_nextLockStateUpdateTs = millis() + _retryDelay;
}
return;
@@ -438,28 +474,22 @@ void NukiWrapper::updateKeyTurnerState()
void NukiWrapper::updateBatteryState()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
Log->println("Querying lock battery state");
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying lock battery state: "));
Log->print(F("Result (attempt "));
Log->print(_retryCount + 1);
Log->print("): ");
result = _nukiLock.requestBatteryReport(&_batteryReport);
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
printCommandResult(result);
@@ -482,6 +512,13 @@ void NukiWrapper::updateConfig()
{
if(_preferences->getUInt(preference_nuki_id_lock, 0) == 0 || _retryConfigCount == 10)
{
char uidString[20];
itoa(_nukiConfig.nukiId, uidString, 16);
Log->print(F("Saving Nuki ID to preferences ("));
Log->print(_nukiConfig.nukiId);
Log->print(" / ");
Log->print(uidString);
Log->println(")");
_preferences->putUInt(preference_nuki_id_lock, _nukiConfig.nukiId);
}
@@ -498,37 +535,30 @@ void NukiWrapper::updateConfig()
const int pinStatus = _preferences->getInt(preference_lock_pin_status, 4);
if(isPinSet()) {
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
Log->println(F("Nuki Lock PIN is set"));
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
result = _nukiLock.verifySecurityPin();
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if(result != Nuki::CmdResult::Success)
{
if(pinStatus != 2) {
Log->println(F("Nuki Lock PIN is invalid"));
if(pinStatus != 2) {
_preferences->putInt(preference_lock_pin_status, 2);
}
}
else
{
Log->println(F("Nuki Lock PIN is valid"));
if(pinStatus != 1) {
_preferences->putInt(preference_lock_pin_status, 1);
}
@@ -536,6 +566,7 @@ void NukiWrapper::updateConfig()
}
else
{
Log->println(F("Nuki Lock PIN is not set"));
if(pinStatus != 0) {
_preferences->putInt(preference_lock_pin_status, 0);
}
@@ -543,12 +574,14 @@ void NukiWrapper::updateConfig()
}
else
{
Log->println(F("Invalid/Unexpected config recieved, retrying"));
expectedConfig = false;
++_retryConfigCount;
}
}
else
{
Log->println(F("Invalid/Unexpected config recieved, retrying"));
expectedConfig = false;
++_retryConfigCount;
}
@@ -559,6 +592,7 @@ void NukiWrapper::updateConfig()
}
else
{
Log->println(F("Invalid/Unexpected advanced config recieved, retrying"));
expectedConfig = false;
++_retryConfigCount;
}
@@ -573,38 +607,27 @@ void NukiWrapper::updateAuthData(bool retrieved)
{
if(!isPinValid())
{
Log->println(F("No valid PIN set"));
Log->println(F("No valid Nuki Lock PIN set"));
return;
}
if(!retrieved)
{
delay(250);
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Retrieve log entries: "));
result = _nukiLock.retrieveLogEntries(0, _preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG), 1, false);
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
Log->println(result);
printCommandResult(result);
if(result == Nuki::CmdResult::Success)
{
@@ -657,28 +680,18 @@ void NukiWrapper::updateKeypad(bool retrieved)
if(!retrieved)
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying lock keypad: "));
result = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
printCommandResult(result);
@@ -728,28 +741,18 @@ void NukiWrapper::updateTimeControl(bool retrieved)
if(!retrieved)
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Querying lock time control: "));
result = _nukiLock.retrieveTimeControlEntries();
_taskRunning = false;
delay(250);
if(result != Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
printCommandResult(result);
@@ -977,7 +980,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
_statusUpdated = true;
_network->publishStatusUpdated(_statusUpdated);
NukiLock::lockstateToString((NukiLock::LockState)_network->_offState, str);
_network->publishString(mqtt_topic_lock_state, str);
_network->publishString(mqtt_topic_lock_state, str, true);
Log->print(F("Lockstate: "));
Log->println(str);
@@ -997,7 +1000,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
Log->print(F("Doorsensor state: "));
Log->println(str);
_network->publishString(mqtt_topic_lock_door_sensor_state, str);
_network->publishString(mqtt_topic_lock_door_sensor_state, str, true);
}
else if(strcmp(topic, mqtt_topic_official_batteryCritical) == 0)
{
@@ -1006,7 +1009,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
Log->print(F("Battery critical: "));
Log->println(_network->_offCritical);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_critical, _network->_offCritical);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_critical, _network->_offCritical, true);
publishBatteryJson = true;
}
else if(strcmp(topic, mqtt_topic_official_batteryCharging) == 0)
@@ -1016,7 +1019,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
Log->print(F("Battery charging: "));
Log->println(_network->_offCharging);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_charging, _network->_offCharging);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_charging, _network->_offCharging, true);
publishBatteryJson = true;
}
else if(strcmp(topic, mqtt_topic_official_batteryChargeState) == 0)
@@ -1026,19 +1029,19 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
Log->print(F("Battery level: "));
Log->println(_network->_offChargeState);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishInt(mqtt_topic_battery_level, _network->_offChargeState);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishInt(mqtt_topic_battery_level, _network->_offChargeState, true);
publishBatteryJson = true;
}
else if(strcmp(topic, mqtt_topic_official_keypadBatteryCritical) == 0)
{
_network->_offKeypadCritical = (strcmp(value, "true") == 0 ? 1 : 0);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_keypad_critical, _network->_offKeypadCritical);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_keypad_critical, _network->_offKeypadCritical, true);
publishBatteryJson = true;
}
else if(strcmp(topic, mqtt_topic_official_doorsensorBatteryCritical) == 0)
{
_network->_offDoorsensorCritical = (strcmp(value, "true") == 0 ? 1 : 0);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_doorsensor_critical, _network->_offDoorsensorCritical);
if(!_preferences->getBool(preference_disable_non_json, false)) _network->publishBool(mqtt_topic_battery_doorsensor_critical, _network->_offDoorsensorCritical, true);
publishBatteryJson = true;
}
else if(strcmp(topic, mqtt_topic_official_commandResponse) == 0)
@@ -1068,11 +1071,11 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
memset(&str, 0, sizeof(str));
lockactionToString((NukiLock::LockAction)_network->_offLockAction, str);
_network->publishString(mqtt_topic_lock_last_lock_action, str);
_network->publishString(mqtt_topic_lock_last_lock_action, str, true);
memset(&str, 0, sizeof(str));
triggerToString((NukiLock::Trigger)_network->_offTrigger, str);
_network->publishString(mqtt_topic_lock_trigger, str);
_network->publishString(mqtt_topic_lock_trigger, str, true);
if(_network->_offAuthId > 0 || _network->_offCodeId > 0)
{
@@ -1098,7 +1101,7 @@ void NukiWrapper::onOfficialUpdateReceived(const char *topic, const char *value)
jsonBattery["keypadCritical"] = _network->_offKeypadCritical ? "1" : "0";
jsonBattery["doorSensorCritical"] = _network->_offDoorsensorCritical ? "1" : "0";
serializeJson(jsonBattery, _resbuf, sizeof(_resbuf));
_network->publishString(mqtt_topic_battery_basic_json, _resbuf);
_network->publishString(mqtt_topic_battery_basic_json, _resbuf, true);
}
}
@@ -1147,16 +1150,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
nukiLockPreferences->getBytes(preference_conf_lock_basic_acl, &basicLockConfigAclPrefs, sizeof(basicLockConfigAclPrefs));
nukiLockPreferences->getBytes(preference_conf_lock_advanced_acl, &advancedLockConfigAclPrefs, sizeof(advancedLockConfigAclPrefs));
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
for(int i=0; i < 16; i++)
{
if(json[basicKeys[i]])
@@ -1176,14 +1169,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(basicKeys[i], "name") == 0)
{
if(strlen(jsonchar) <= 32)
@@ -1359,12 +1344,11 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
else jsonResult[basicKeys[i]] = "invalidValue";
}
if(cmdResult != Nuki::CmdResult::Success) {
delay(250);
if(!cmdResult == Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if(cmdResult == Nuki::CmdResult::Success) basicUpdated = true;
@@ -1398,14 +1382,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(advancedKeys[j], "unlockedPositionOffsetDegrees") == 0)
{
const int16_t keyvalue = atoi(jsonchar);
@@ -1653,12 +1629,11 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
else jsonResult[advancedKeys[j]] = "invalidValue";
}
if(cmdResult != Nuki::CmdResult::Success) {
delay(250);
if(!cmdResult == Nuki::CmdResult::Success) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if(cmdResult == Nuki::CmdResult::Success) advancedUpdated = true;
@@ -1673,8 +1648,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *value)
}
}
_taskRunning = false;
nukiLockPreferences->end();
if(basicUpdated || advancedUpdated) jsonResult["general"] = "success";
@@ -1791,14 +1764,6 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(command, "add") == 0)
{
if(name == "" || name == "--")
@@ -1822,9 +1787,8 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
size_t nameLen = name.length();
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
_taskRunning = true;
result = _nukiLock.addKeypadEntry(entry);
_taskRunning = false;
delay(250);
Log->print("Add keypad code: "); Log->println((int)result);
updateKeypad(false);
}
@@ -1836,9 +1800,8 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
return;
}
_taskRunning = true;
result = _nukiLock.deleteKeypadEntry(id);
_taskRunning = false;
delay(250);
Log->print("Delete keypad code: "); Log->println((int)result);
updateKeypad(false);
}
@@ -1872,13 +1835,12 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
memcpy(&entry.name, name.c_str(), nameLen > 20 ? 20 : nameLen);
entry.code = codeInt;
entry.enabled = enabled == 0 ? 0 : 1;
_taskRunning = true;
result = _nukiLock.updateKeypadEntry(entry);
_taskRunning = false;
delay(250);
Log->print("Update keypad code: "); Log->println((int)result);
updateKeypad(false);
}
else if(command == "--")
else if(strcmp(command, "--") == 0)
{
return;
}
@@ -1892,8 +1854,6 @@ void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, c
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if((int)result != -1)
@@ -1989,20 +1949,11 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(action, "delete") == 0) {
if(idExists)
{
_taskRunning = true;
result = _nukiLock.deleteKeypadEntry(codeId);
_taskRunning = false;
delay(250);
Log->print(F("Delete keypad code: "));
Log->println((int)result);
}
@@ -2188,9 +2139,8 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
entry.allowedUntilTimeMin = allowedUntilTimeAr[1];
}
_taskRunning = true;
result = _nukiLock.addKeypadEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Add keypad code: "));
Log->println((int)result);
}
@@ -2208,17 +2158,8 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
return;
}
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Nuki::CmdResult resultKp = _nukiLock.retrieveKeypadEntries(0, _preferences->getInt(preference_keypad_max_entries, MAX_KEYPAD));
_taskRunning = false;
delay(250);
bool foundExisting = false;
if(resultKp == Nuki::CmdResult::Success)
@@ -2346,9 +2287,8 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
}
}
_taskRunning = true;
result = _nukiLock.updateKeypadEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Update keypad code: "));
Log->println((int)result);
}
@@ -2363,8 +2303,6 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
updateKeypad(false);
@@ -2453,20 +2391,11 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
if(strcmp(action, "delete") == 0) {
if(idExists)
{
_taskRunning = true;
result = _nukiLock.removeTimeControlEntry(entryId);
_taskRunning = false;
delay(250);
Log->print(F("Delete time control: "));
Log->println((int)result);
}
@@ -2525,9 +2454,8 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
entry.lockAction = timeControlLockAction;
_taskRunning = true;
result = _nukiLock.addTimeControlEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Add time control: "));
Log->println((int)result);
}
@@ -2539,17 +2467,8 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
return;
}
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Nuki::CmdResult resultTc = _nukiLock.retrieveTimeControlEntries();
_taskRunning = false;
delay(250);
bool foundExisting = false;
if(resultTc == Nuki::CmdResult::Success)
@@ -2570,7 +2489,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
timeAr[0] = entry.timeHour;
timeAr[1] = entry.timeMin;
}
if(lockAction.length() < 1) timeControlLockAction = entry.lockAction;
if(lockAction.length() < 1) timeControlLockAction = entry.lockAction;
}
if(!foundExisting)
@@ -2599,9 +2518,8 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
entry.lockAction = timeControlLockAction;
_taskRunning = true;
result = _nukiLock.updateTimeControlEntry(entry);
_taskRunning = false;
delay(250);
Log->print(F("Update time control: "));
Log->println((int)result);
}
@@ -2616,8 +2534,6 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
if((int)result != -1)
@@ -2658,6 +2574,7 @@ void NukiWrapper::notify(Nuki::EventType eventType)
{
if(_preferences->getBool(preference_official_hybrid, false) && _intervalHybridLockstate > 0 && millis() > (_intervalHybridLockstate * 1000))
{
Log->println("OffKeyTurnerStatusUpdated");
_statusUpdated = true;
_nextHybridLockStateUpdateTs = millis() + _intervalHybridLockstate * 1000;
}
@@ -2665,6 +2582,7 @@ void NukiWrapper::notify(Nuki::EventType eventType)
{
if(eventType == Nuki::EventType::KeyTurnerStatusUpdated)
{
Log->println("KeyTurnerStatusUpdated");
_statusUpdated = true;
_network->publishStatusUpdated(_statusUpdated);
}
@@ -2674,29 +2592,22 @@ void NukiWrapper::notify(Nuki::EventType eventType)
void NukiWrapper::readConfig()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
Log->print(F("Reading config. Result: "));
result = _nukiLock.requestConfig(&_nukiConfig);
_taskRunning = false;
delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
Log->print(F("Config valid: "));
Log->println(_nukiConfigValid);
if(!_nukiConfigValid) {
++_retryCount;
Log->println("Retrying in 1s");
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
char resultStr[20];
@@ -2706,29 +2617,19 @@ void NukiWrapper::readConfig()
void NukiWrapper::readAdvancedConfig()
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
result = _nukiLock.requestAdvancedConfig(&_nukiAdvancedConfig);
_taskRunning = false;
delay(250);
_nukiAdvancedConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiAdvancedConfigValid) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
char resultStr[20];
@@ -2760,31 +2661,21 @@ bool NukiWrapper::hasDoorSensor() const
void NukiWrapper::disableHASS()
{
if(!_nukiConfigValid) // only ask for config once to save battery life
if(!_nukiConfigValid)
{
Nuki::CmdResult result;
Nuki::CmdResult result = (Nuki::CmdResult)-1;
_retryCount = 0;
while(_retryCount < _nrOfRetries + 1)
{
int loop = 0;
while(_taskRunning && loop < 600)
{
Log->println("Waiting to run Nuki BLE command");
vTaskDelay( 50 / portTICK_PERIOD_MS);
++loop;
}
_taskRunning = true;
result = _nukiLock.requestConfig(&_nukiConfig);
_taskRunning = false;
delay(250);
_nukiConfigValid = result == Nuki::CmdResult::Success;
if(!_nukiConfigValid) {
++_retryCount;
}
else break;
vTaskDelay( 1000 / portTICK_PERIOD_MS);
}
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "NetworkLock.h"
#include "NukiNetworkLock.h"
#include "NukiConstants.h"
#include "NukiDataTypes.h"
#include "BleScanner.h"
@@ -12,7 +12,7 @@
class NukiWrapper : public Nuki::SmartlockEventHandler
{
public:
NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NetworkLock* network, Gpio* gpio, Preferences* preferences);
NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, Gpio* gpio, Preferences* preferences);
virtual ~NukiWrapper();
void initialize(const bool& firstStart);
@@ -86,7 +86,7 @@ private:
NukiDeviceId* _deviceId = nullptr;
NukiLock::NukiLock _nukiLock;
BleScanner::Scanner* _bleScanner = nullptr;
NetworkLock* _network = nullptr;
NukiNetworkLock* _network = nullptr;
Gpio* _gpio = nullptr;
Preferences* _preferences;
int _intervalLockstate = 0; // seconds
@@ -97,7 +97,6 @@ private:
int _restartBeaconTimeout = 0; // seconds
bool _publishAuthData = false;
bool _clearAuthData = false;
bool _taskRunning = false;
std::vector<uint16_t> _keypadCodeIds;
std::vector<uint8_t> _timeControlIds;

View File

@@ -44,7 +44,6 @@
#define preference_hostname (char*)"hostname"
#define preference_network_timeout (char*)"nettmout"
#define preference_restart_on_disconnect (char*)"restdisc"
#define preference_restart_timer (char*)"resttmr"
#define preference_restart_ble_beacon_lost (char*)"rstbcn"
#define preference_query_interval_lockstate (char*)"lockStInterval"
#define preference_query_interval_configuration (char*)"configInterval"
@@ -93,43 +92,66 @@
#define preference_official_hybrid_actions (char*)"hybridAct"
#define preference_official_hybrid_retry (char*)"hybridRtry"
#define preference_query_interval_hybrid_lockstate (char*)"hybridTimer"
#define preference_ota_main_url (char*)"otaMainUrl"
#define preference_ota_updater_url (char*)"otaUpdUrl"
#define preference_update_from_mqtt (char*)"updMqtt"
#define preference_show_secrets (char*)"showSecr"
class DebugPreferences
{
private:
std::vector<char*> _keys =
{
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_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_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_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_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_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,
preference_register_as_app, preference_register_opener_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user, preference_cred_password,
preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info, preference_presence_detection_timeout, preference_official_hybrid, preference_query_interval_hybrid_lockstate,
preference_official_hybrid_actions, preference_official_hybrid_retry, preference_has_mac_saved, preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2,
preference_latest_version, preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries,
preference_timecontrol_max_entries
preference_register_as_app, preference_register_opener_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user,
preference_cred_password, preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info, preference_presence_detection_timeout,
preference_official_hybrid, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry, preference_has_mac_saved,
preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2, preference_latest_version, 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
};
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_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,
};
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_restart_on_disconnect,
preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, 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_has_mac_saved, preference_publish_debug_info,
preference_network_wifi_fallback_disabled, preference_official_hybrid, preference_official_hybrid_actions, preference_official_hybrid_retry, preference_conf_info_enabled, preference_disable_non_json
preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_find_best_rssi,
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_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled, preference_official_hybrid,
preference_official_hybrid_actions, preference_official_hybrid_retry, preference_conf_info_enabled, preference_disable_non_json, preference_update_from_mqtt
};
std::vector<char*> _bytePrefs =
{
preference_acl, preference_conf_info_enabled, preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl,
preference_conf_opener_advanced_acl, preference_gpio_configuration
};
std::vector<char*> _intPrefs =
{
preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, preference_mqtt_broker_port,
preference_lock_pin_status, preference_opener_pin_status, 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_buffer_size, preference_network_hardware,
preference_rssi_publish_interval, preference_network_timeout, preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_command_nr_of_retries,
preference_command_retry_delay, preference_presence_detection_timeout, preference_query_interval_hybrid_lockstate, preference_latest_version,
preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries
};
std::vector<char*> _charPrefs =
{
preference_has_mac_byte_0, preference_has_mac_byte_1, preference_has_mac_byte_2
};
const bool isRedacted(const char* key) const
{
return std::find(_redact.begin(), _redact.end(), key) != _redact.end();
@@ -270,6 +292,30 @@ private:
}
public:
const std::vector<char*> getPreferencesKeys()
{
return _keys;
}
const std::vector<char*> getPreferencesRedactedKeys()
{
return _redact;
}
const std::vector<char*> getPreferencesBoolKeys()
{
return _boolPrefs;
}
const std::vector<char*> getPreferencesByteKeys()
{
return _bytePrefs;
}
const std::vector<char*> getPreferencesIntKeys()
{
return _intPrefs;
}
const std::vector<char*> getPreferencesCharKeys()
{
return _charPrefs;
}
const String preferencesToString(Preferences *preferences)
{
String s = "";

View File

@@ -213,6 +213,24 @@ void PresenceDetection::onResult(NimBLEAdvertisedDevice *device)
// }
}
}
else
{
std::string nameStr = "-";
i=0;
len = nameStr.length();
while(i < len && i < sizeof(pdDevice->name)-1)
{
pdDevice->name[i] = nameStr.at(i);
++i;
}
pdDevice->timestamp = millis();
{
std::lock_guard<std::mutex> lock(mtx);
_devices[addr] = pdDevice;
}
}
}
// if(device->haveName())
@@ -232,4 +250,4 @@ void PresenceDetection::onResult(NimBLEAdvertisedDevice *device)
bool PresenceDetection::enabled()
{
return _timeout > 0;
}
}

View File

@@ -19,6 +19,8 @@ enum class RestartReason
OTATimeout,
OTAAborted,
OTAUnknownState,
OTAReboot,
ImportCompleted,
DeviceUnpaired,
NukiHubReset,
NotApplicable
@@ -99,6 +101,10 @@ inline static String getRestartReason()
return "OTAAborted";
case RestartReason::OTAUnknownState:
return "OTAUnknownState";
case RestartReason::OTAReboot:
return "RebootToOTA";
case RestartReason::ImportCompleted:
return "ConfigImportCompleted";
case RestartReason::DeviceUnpaired:
return "DeviceUnpaired";
case RestartReason::NukiHubReset:
@@ -142,9 +148,11 @@ inline static String getEspRestartReason()
}
}
#ifndef NUKI_HUB_UPDATER
inline bool rebuildGpio()
{
bool rebGpio = rebuildGpioRequested;
rebuildGpioRequested = false;
return restartReason_isValid && rebGpio;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -2,15 +2,15 @@
#include <Preferences.h>
#include <WebServer.h>
#include "NukiWrapper.h"
#include "NetworkLock.h"
#include "NukiOpenerWrapper.h"
#include "Ota.h"
#ifndef NUKI_HUB_UPDATER
#include "NukiWrapper.h"
#include "NukiNetworkLock.h"
#include "NukiOpenerWrapper.h"
#include "Gpio.h"
extern TaskHandle_t networkTaskHandle;
extern TaskHandle_t nukiTaskHandle;
extern TaskHandle_t presenceDetectionTaskHandle;
enum class TokenType
{
@@ -24,36 +24,44 @@ enum class TokenType
QueryIntervalBattery,
};
#else
#include "NukiNetwork.h"
#endif
extern TaskHandle_t networkTaskHandle;
class WebCfgServer
{
public:
WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Network* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal);
#ifndef NUKI_HUB_UPDATER
WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, NukiNetwork* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType);
#else
WebCfgServer(NukiNetwork* network, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal, uint8_t partitionType);
#endif
~WebCfgServer() = default;
void initialize();
void update();
private:
#ifndef NUKI_HUB_UPDATER
void sendSettings();
bool processArgs(String& message);
bool processImport(String& message);
void processGpioArgs();
void buildHtml(String& response);
void buildAccLvlHtml(String& response);
void buildCredHtml(String& response);
void buildOtaHtml(String& response, bool errored);
void buildOtaCompletedHtml(String& response);
void buildImportExportHtml(String& response);
void buildMqttConfigHtml(String& response);
void buildStatusHtml(String& response);
void buildAdvancedConfigHtml(String& response);
void buildNukiConfigHtml(String& response);
void buildGpioConfigHtml(String& response);
void buildConfirmHtml(String& response, const String &message, uint32_t redirectDelay = 5);
void buildConfigureWifiHtml(String& response);
void buildInfoHtml(String& response);
void sendCss();
void sendFavicon();
void processUnpair(bool opener);
void processFactoryReset();
void buildHtmlHeader(String& response, String additionalHeader = "");
void printInputField(String& response, const char* token, const char* description, const char* value, const size_t& maxLength, const char* id, const bool& isPassword = false, const bool& showLengthRestriction = false);
void printInputField(String& response, const char* token, const char* description, const int value, size_t maxLength, const char* id);
void printCheckBox(String& response, const char* token, const char* description, const bool value, const char* htmlClass);
@@ -70,14 +78,26 @@ private:
void printParameter(String& response, const char* description, const char* value, const char *link = "", const char *id = "");
String generateConfirmCode();
NukiWrapper* _nuki = nullptr;
NukiOpenerWrapper* _nukiOpener = nullptr;
Gpio* _gpio = nullptr;
bool _pinsConfigured = false;
bool _brokerConfigured = false;
String _confirmCode = "----";
#endif
void buildConfirmHtml(String& response, const String &message, uint32_t redirectDelay = 5);
void buildOtaHtml(String& response, bool errored);
void buildOtaCompletedHtml(String& response);
void sendCss();
void sendFavicon();
void buildHtmlHeader(String& response, String additionalHeader = "");
void waitAndProcess(const bool blocking, const uint32_t duration);
void handleOtaUpload();
WebServer _server;
NukiWrapper* _nuki = nullptr;
NukiOpenerWrapper* _nukiOpener = nullptr;
Network* _network = nullptr;
Gpio* _gpio = nullptr;
NukiNetwork* _network = nullptr;
Preferences* _preferences = nullptr;
Ota _ota;
@@ -85,13 +105,9 @@ private:
char _credUser[31] = {0};
char _credPassword[31] = {0};
bool _allowRestartToPortal = false;
bool _pinsConfigured = false;
bool _brokerConfigured = false;
uint8_t _partitionType = 0;
uint32_t _transferredSize = 0;
unsigned long _otaStartTs = 0;
String _hostname;
String _confirmCode = "----";
bool _enabled = true;
};

View File

@@ -3,7 +3,7 @@
// escaped by https://www.cescaper.com/
// source: https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css
const char stylecss[] = ":root{--nc-font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';--nc-font-mono:Consolas,monaco,'Ubuntu Mono','Liberation Mono','Courier New',Courier,monospace;--nc-tx-1:#000;--nc-tx-2:#1a1a1a;--nc-bg-1:#fff;--nc-bg-2:#f6f8fa;--nc-bg-3:#e5e7eb;--nc-lk-1:#0070f3;--nc-lk-2:#0366d6;--nc-lk-tx:#fff;--nc-ac-1:#79ffe1;--nc-ac-tx:#0c4047}@media(prefers-color-scheme:dark){:root{--nc-tx-1:#fff;--nc-tx-2:#eee;--nc-bg-1:#000;--nc-bg-2:#111;--nc-bg-3:#222;--nc-lk-1:#3291ff;--nc-lk-2:#0070f3;--nc-lk-tx:#fff;--nc-ac-1:#7928ca;--nc-ac-tx:#fff}}*{margin:0;padding:0}img,input,option,p,table,textarea,ul{margin-bottom:1rem}button,html,input,select{font-family:var(--nc-font-sans)}body{margin:0 auto;max-width:750px;padding:2rem;border-radius:6px;overflow-x:hidden;word-break:normal;overflow-wrap:anywhere;background:var(--nc-bg-1);color:var(--nc-tx-2);font-size:1.03rem;line-height:1.5}::selection{background:var(--nc-ac-1);color:var(--nc-ac-tx)}h1,h2,h3,h4,h5,h6{line-height:1;color:var(--nc-tx-1);padding-top:.875rem}h1,h2,h3{color:var(--nc-tx-1);padding-bottom:2px;margin-bottom:8px;border-bottom:1px solid var(--nc-bg-2)}h4,h5,h6{margin-bottom:.3rem}h1{font-size:2.25rem}h2{font-size:1.85rem}h3{font-size:1.55rem}h4{font-size:1.25rem}h5{font-size:1rem}h6{font-size:.875rem}a{color:var(--nc-lk-1)}a:hover{color:var(--nc-lk-2)}abbr{cursor:help}abbr:hover{cursor:help}a button,button,input[type=button],input[type=reset],input[type=submit]{font-size:1rem;display:inline-block;padding:6px 12px;text-align:center;text-decoration:none;white-space:nowrap;background:var(--nc-lk-1);color:var(--nc-lk-tx);border:0;border-radius:4px;box-sizing:border-box;cursor:pointer;color:var(--nc-lk-tx)}a button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default;opacity:.5;cursor:not-allowed}.button:focus,.button:hover,button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]:focus,input[type=submit]:hover{background:var(--nc-lk-2)}table{border-collapse:collapse;width:100%}td,th{border:1px solid var(--nc-bg-3);text-align:left;padding:.5rem}th{background:var(--nc-bg-2)}tr:nth-child(even){background:var(--nc-bg-2)}textarea{max-width:100%}input,select,textarea{padding:6px 12px;margin-bottom:.5rem;background:var(--nc-bg-2);color:var(--nc-tx-2);border:1px solid var(--nc-bg-3);border-radius:4px;box-shadow:none;box-sizing:border-box}img{max-width:100%}td>input{margin-top:0;margin-bottom:0}td>textarea{margin-top:0;margin-bottom:0}td>select{margin-top:0;margin-bottom:0}.warning{color:red}@media only screen and (max-width:600px){.adapt td{display:block}.adapt input[type=text],.adapt input[type=password],.adapt input[type=submit],.adapt textarea,.adapt select{width:100%}.adapt td:has(input[type=checkbox]){text-align:center}.adapt input[type=checkbox]{width:1.5em;height:1.5em}.adapt table td:first-child{border-bottom:0}.adapt table td:last-child{border-top:0}#tblnav a li>span{max-width:140px}}#tblnav a{border:0;border-bottom:1px solid;display:block;font-size:1rem;font-weight:bold;padding:.6rem 0;line-height:1;color:var(--nc-tx-1);text-decoration:none;background:linear-gradient(to left,transparent 50%,rgba(255,255,255,0.4) 50%) right;background-size:200% 100%;transition:all .2s ease}#tblnav a:nth-child(even){background:linear-gradient(to left,var(--nc-bg-2) 50%,rgba(255,255,255,0.4) 50%) right;background-size:200% 100%}#tblnav a:hover{background-position:left;transition:all .45s ease}#tblnav a:active{background:var(--nc-lk-1);transition:all .15s ease}#tblnav a li{list-style:none;padding:.5rem;display:inline-block;width:100%}#tblnav a li>span{float:right;text-align:right;margin-right:10px;color:#f70;font-weight:100;font-style:italic;display:block}.tdbtn{text-align:center;vertical-align:middle}";
const char stylecss[] = ":root{--nc-font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';--nc-font-mono:Consolas,monaco,'Ubuntu Mono','Liberation Mono','Courier New',Courier,monospace;--nc-tx-1:#000;--nc-tx-2:#1a1a1a;--nc-bg-1:#fff;--nc-bg-2:#f6f8fa;--nc-bg-3:#e5e7eb;--nc-lk-1:#0070f3;--nc-lk-2:#0366d6;--nc-lk-tx:#fff;--nc-ac-1:#79ffe1;--nc-ac-tx:#0c4047}@media(prefers-color-scheme:dark){:root{--nc-tx-1:#fff;--nc-tx-2:#eee;--nc-bg-1:#000;--nc-bg-2:#111;--nc-bg-3:#222;--nc-lk-1:#3291ff;--nc-lk-2:#0070f3;--nc-lk-tx:#fff;--nc-ac-1:#7928ca;--nc-ac-tx:#fff}}*{margin:0;padding:0}img,input,option,p,table,textarea,ul{margin-bottom:1rem}button,html,input,select{font-family:var(--nc-font-sans)}body{margin:0 auto;max-width:750px;padding:2rem;border-radius:6px;overflow-x:hidden;word-break:normal;overflow-wrap:anywhere;background:var(--nc-bg-1);color:var(--nc-tx-2);font-size:1.03rem;line-height:1.5}::selection{background:var(--nc-ac-1);color:var(--nc-ac-tx)}h1,h2,h3,h4,h5,h6{line-height:1;color:var(--nc-tx-1);padding-top:.875rem}h1,h2,h3{color:var(--nc-tx-1);padding-bottom:2px;margin-bottom:8px;border-bottom:1px solid var(--nc-bg-2)}h4,h5,h6{margin-bottom:.3rem}h1{font-size:2.25rem}h2{font-size:1.85rem}h3{font-size:1.55rem}h4{font-size:1.25rem}h5{font-size:1rem}h6{font-size:.875rem}a{color:var(--nc-lk-1)}a:hover{color:var(--nc-lk-2) !important;}abbr{cursor:help}abbr:hover{cursor:help}a button,button,input[type=button],input[type=reset],input[type=submit]{font-size:1rem;display:inline-block;padding:6px 12px;text-align:center;text-decoration:none;white-space:nowrap;background:var(--nc-lk-1);color:var(--nc-lk-tx);border:0;border-radius:4px;box-sizing:border-box;cursor:pointer;color:var(--nc-lk-tx)}a button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default;opacity:.5;cursor:not-allowed}.button:focus,.button:hover,button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]:focus,input[type=submit]:hover{background:var(--nc-lk-2)}table{border-collapse:collapse;width:100%}td,th{border:1px solid var(--nc-bg-3);text-align:left;padding:.5rem}th{background:var(--nc-bg-2)}tr:nth-child(even){background:var(--nc-bg-2)}textarea{max-width:100%}input,select,textarea{padding:6px 12px;margin-bottom:.5rem;background:var(--nc-bg-2);color:var(--nc-tx-2);border:1px solid var(--nc-bg-3);border-radius:4px;box-shadow:none;box-sizing:border-box}img{max-width:100%}td>input{margin-top:0;margin-bottom:0}td>textarea{margin-top:0;margin-bottom:0}td>select{margin-top:0;margin-bottom:0}.warning{color:red}@media only screen and (max-width:600px){.adapt td{display:block}.adapt input[type=text],.adapt input[type=password],.adapt input[type=submit],.adapt textarea,.adapt select{width:100%}.adapt td:has(input[type=checkbox]){text-align:center}.adapt input[type=checkbox]{width:1.5em;height:1.5em}.adapt table td:first-child{border-bottom:0}.adapt table td:last-child{border-top:0}#tblnav a li>span{max-width:140px}}#tblnav a{border:0;border-bottom:1px solid;display:block;font-size:1rem;font-weight:bold;padding:.6rem 0;line-height:1;color:var(--nc-tx-1);text-decoration:none;background:linear-gradient(to left,transparent 50%,rgba(255,255,255,0.4) 50%) right;background-size:200% 100%;transition:all .2s ease}#tblnav a:nth-child(even){background:linear-gradient(to left,var(--nc-bg-2) 50%,rgba(255,255,255,0.4) 50%) right;background-size:200% 100%}#tblnav a:hover{background-position:left;transition:all .45s ease}#tblnav a:active{background:var(--nc-lk-1);transition:all .15s ease}#tblnav a li{list-style:none;padding:.5rem;display:inline-block;width:100%}#tblnav a li>span{float:right;text-align:right;margin-right:10px;color:#f70;font-weight:100;font-style:italic;display:block}.tdbtn{text-align:center;vertical-align:middle}";
// converted to char array by https://notisrac.github.io/FileToCArray/
const unsigned char favicon_32x32[] = {

View File

@@ -1,40 +1,62 @@
#include "Arduino.h"
#include "NukiWrapper.h"
#include "NetworkLock.h"
#include "WebCfgServer.h"
#include <RTOS.h>
#include "PreferencesKeys.h"
#include "PresenceDetection.h"
#include "hardware/W5500EthServer.h"
#include "hardware/WifiEthServer.h"
#include "NukiOpenerWrapper.h"
#include "Gpio.h"
#include "Logger.h"
#include "Config.h"
#include "RestartReason.h"
#include "CharBuffer.h"
#include "NukiDeviceId.h"
#define IS_VALID_DETECT 0xa00ab00bc00bd00d;
Network* network = nullptr;
NetworkLock* networkLock = nullptr;
NetworkOpener* networkOpener = nullptr;
WebCfgServer* webCfgServer = nullptr;
#include "Arduino.h"
#include "hardware/W5500EthServer.h"
#include "hardware/WifiEthServer.h"
#include "esp_crt_bundle.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "Config.h"
#ifndef NUKI_HUB_UPDATER
#include "NukiWrapper.h"
#include "NukiNetworkLock.h"
#include "PresenceDetection.h"
#include "NukiOpenerWrapper.h"
#include "Gpio.h"
#include "CharBuffer.h"
#include "NukiDeviceId.h"
#include "WebCfgServer.h"
#include "Logger.h"
#include "PreferencesKeys.h"
#include "RestartReason.h"
NukiNetworkLock* networkLock = nullptr;
NukiNetworkOpener* networkOpener = nullptr;
BleScanner::Scanner* bleScanner = nullptr;
NukiWrapper* nuki = nullptr;
NukiOpenerWrapper* nukiOpener = nullptr;
PresenceDetection* presenceDetection = nullptr;
NukiDeviceId* deviceIdLock = nullptr;
NukiDeviceId* deviceIdOpener = nullptr;
Preferences* preferences = nullptr;
EthServer* ethServer = nullptr;
Gpio* gpio = nullptr;
bool lockEnabled = false;
bool openerEnabled = false;
TaskHandle_t nukiTaskHandle = nullptr;
TaskHandle_t presenceDetectionTaskHandle = nullptr;
unsigned long restartTs = (2^32) - 5 * 60000;
#else
#include "../../src/WebCfgServer.h"
#include "../../src/Logger.h"
#include "../../src/PreferencesKeys.h"
#include "../../src/Config.h"
#include "../../src/RestartReason.h"
#include "../../src/NukiNetwork.h"
unsigned long restartTs = 10 * 60000;
#endif
NukiNetwork* network = nullptr;
WebCfgServer* webCfgServer = nullptr;
Preferences* preferences = nullptr;
EthServer* ethServer = nullptr;
RTC_NOINIT_ATTR int restartReason;
RTC_NOINIT_ATTR uint64_t restartReasonValidDetect;
RTC_NOINIT_ATTR bool rebuildGpioRequested;
@@ -45,9 +67,8 @@ RTC_NOINIT_ATTR int8_t bootloopCounter;
bool restartReason_isValid;
RestartReason currentRestartReason = RestartReason::NotApplicable;
TaskHandle_t otaTaskHandle = nullptr;
TaskHandle_t networkTaskHandle = nullptr;
TaskHandle_t nukiTaskHandle = nullptr;
TaskHandle_t presenceDetectionTaskHandle = nullptr;
void networkTask(void *pvParameters)
{
@@ -61,6 +82,8 @@ void networkTask(void *pvParameters)
}
bool connected = network->update();
#ifndef NUKI_HUB_UPDATER
if(connected && openerEnabled)
{
networkOpener->update();
@@ -70,6 +93,9 @@ void networkTask(void *pvParameters)
{
webCfgServer->update();
}
#else
webCfgServer->update();
#endif
// millis() is about to overflow. Restart device to prevent problems with overflow
if(millis() > restartTs)
@@ -80,16 +106,10 @@ void networkTask(void *pvParameters)
}
delay(100);
// if(wmts < millis())
// {
// Serial.print("# ");
// Serial.println(uxTaskGetStackHighWaterMark(NULL));
// wmts = millis() + 60000;
// }
}
}
#ifndef NUKI_HUB_UPDATER
void nukiTask(void *pvParameters)
{
while(true)
@@ -115,13 +135,120 @@ void nukiTask(void *pvParameters)
}
}
#endif
void setupTasks()
uint8_t checkPartition()
{
const esp_partition_t* running_partition = esp_ota_get_running_partition();
Log->print(F("Partition size: "));
Log->println(running_partition->size);
Log->print(F("Partition subtype: "));
Log->println(running_partition->subtype);
if(running_partition->size == 1966080) return 0; //OLD PARTITION TABLE
else if(running_partition->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) return 1; //NEW PARTITION TABLE, RUNNING MAIN APP
else return 2; //NEW PARTITION TABLE, RUNNING UPDATER APP
}
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id) {
case HTTP_EVENT_ERROR:
Log->println("HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
Log->println("HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
Log->println("HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
Log->println("HTTP_EVENT_ON_HEADER");
break;
case HTTP_EVENT_ON_DATA:
Log->println("HTTP_EVENT_ON_DATA");
break;
case HTTP_EVENT_ON_FINISH:
Log->println("HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
Log->println("HTTP_EVENT_DISCONNECTED");
break;
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0))
case HTTP_EVENT_REDIRECT:
Log->println("HTTP_EVENT_REDIRECT");
break;
#endif
}
return ESP_OK;
}
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0))
void otaTask(void *pvParameter)
{
uint8_t partitionType = checkPartition();
String updateUrl;
if(partitionType==1)
{
updateUrl = preferences->getString(preference_ota_updater_url);
preferences->putString(preference_ota_updater_url, "");
}
else
{
updateUrl = preferences->getString(preference_ota_main_url);
preferences->putString(preference_ota_main_url, "");
}
Log->println("Starting OTA task");
esp_http_client_config_t config = {
.url = updateUrl.c_str(),
.event_handler = _http_event_handler,
.crt_bundle_attach = esp_crt_bundle_attach,
.keep_alive_enable = true,
};
esp_https_ota_config_t ota_config = {
.http_config = &config,
};
Log->print(F("Attempting to download update from "));
Log->println(config.url);
esp_err_t ret = esp_https_ota(&ota_config);
if (ret == ESP_OK) {
Log->println("OTA Succeeded, Rebooting...");
esp_ota_set_boot_partition(esp_ota_get_next_update_partition(NULL));
restartEsp(RestartReason::OTACompleted);
} else {
Log->println("Firmware upgrade failed");
restartEsp(RestartReason::OTAAborted);
}
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
#endif
void setupTasks(bool ota)
{
// configMAX_PRIORITIES is 25
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1);
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 1);
if(ota)
{
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1);
#ifndef NUKI_HUB_UPDATER
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 1);
#endif
#else
xTaskCreatePinnedToCore(otaTask, "ota", 8192, NULL, 2, &otaTaskHandle, 1);
#endif
}
else
{
xTaskCreatePinnedToCore(networkTask, "ntw", preferences->getInt(preference_task_size_network, NETWORK_TASK_SIZE), NULL, 3, &networkTaskHandle, 1);
#ifndef NUKI_HUB_UPDATER
xTaskCreatePinnedToCore(nukiTask, "nuki", preferences->getInt(preference_task_size_nuki, NUKI_TASK_SIZE), NULL, 2, &nukiTaskHandle, 1);
#endif
}
}
void initEthServer(const NetworkDeviceType device)
@@ -145,24 +272,22 @@ bool initPreferences()
preferences = new Preferences();
preferences->begin("nukihub", false);
// preferences->putBool(preference_network_wifi_fallback_disabled, false);
#ifndef NUKI_HUB_UPDATER
bool firstStart = !preferences->getBool(preference_started_before);
if(firstStart)
{
preferences->putBool(preference_started_before, true);
preferences->putBool(preference_lock_enabled, true);
preferences->putBool(preference_conf_info_enabled, true);
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
uint32_t basicLockConfigAclPrefs[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
uint32_t basicOpenerConfigAclPrefs[14] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
uint32_t advancedLockConfigAclPrefs[22] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
uint32_t advancedLockConfigAclPrefs[22] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
uint32_t advancedOpenerConfigAclPrefs[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
uint32_t advancedOpenerConfigAclPrefs[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
}
else
@@ -182,7 +307,7 @@ bool initPreferences()
preferences->putBool(preference_keypad_info_enabled, false);
}
switch(preferences->getInt(preference_access_level))
switch(preferences->getInt(preference_access_level, 10))
{
case 0:
{
@@ -244,6 +369,21 @@ bool initPreferences()
preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
break;
}
default:
{
preferences->putBool(preference_keypad_control_enabled, true);
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
uint32_t basicLockConfigAclPrefs[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
uint32_t basicOpenerConfigAclPrefs[14] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
uint32_t advancedLockConfigAclPrefs[22] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
uint32_t advancedOpenerConfigAclPrefs[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
break;
}
}
}
@@ -252,6 +392,9 @@ bool initPreferences()
}
return firstStart;
#else
return false;
#endif
}
void bootloopDetection()
@@ -297,19 +440,30 @@ void setup()
Serial.begin(115200);
Log = &Serial;
Log->print(F("Nuki Hub version ")); Log->println(NUKI_HUB_VERSION);
Log->print(F("Nuki Hub build ")); Log->println(NUKI_HUB_BUILD);
bool firstStart = initPreferences();
preferences->remove(preference_bootloop_counter);
uint8_t partitionType = checkPartition();
initializeRestartReason();
if(preferences->getBool(preference_enable_bootloop_reset, false))
{
bootloopDetection();
}
#ifdef NUKI_HUB_UPDATER
Log->print(F("Nuki Hub OTA version ")); Log->println(NUKI_HUB_VERSION);
Log->print(F("Nuki Hub OTA build ")); Log->println(NUKI_HUB_BUILD);
network = new NukiNetwork(preferences);
network->initialize();
initEthServer(network->networkDeviceType());
webCfgServer = new WebCfgServer(network, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType);
webCfgServer->initialize();
#else
Log->print(F("Nuki Hub version ")); Log->println(NUKI_HUB_VERSION);
Log->print(F("Nuki Hub build ")); Log->println(NUKI_HUB_BUILD);
uint32_t devIdOpener = preferences->getUInt(preference_device_id_opener);
deviceIdLock = new NukiDeviceId(preferences, preference_device_id_lock);
@@ -319,16 +473,11 @@ void setup()
{
deviceIdOpener->assignId(deviceIdLock->get());
}
char16_t buffer_size = preferences->getInt(preference_buffer_size, 4096);
CharBuffer::initialize(buffer_size);
if(preferences->getInt(preference_restart_timer) != 0)
{
preferences->remove(preference_restart_timer);
}
gpio = new Gpio(preferences);
String gpioDesc;
gpio->getConfigurationText(gpioDesc, gpio->pinConfiguration(), "\n\r");
@@ -340,7 +489,7 @@ void setup()
if(preferences->getInt(preference_presence_detection_timeout) >= 0)
{
presenceDetection = new PresenceDetection(preferences, bleScanner, CharBuffer::get(), CHAR_BUFFER_SIZE);
presenceDetection = new PresenceDetection(preferences, bleScanner, CharBuffer::get(), buffer_size);
presenceDetection->initialize();
}
@@ -348,15 +497,16 @@ void setup()
openerEnabled = preferences->getBool(preference_opener_enabled);
const String mqttLockPath = preferences->getString(preference_mqtt_lock_path);
network = new Network(preferences, presenceDetection, gpio, mqttLockPath, CharBuffer::get(), buffer_size);
network = new NukiNetwork(preferences, presenceDetection, gpio, mqttLockPath, CharBuffer::get(), buffer_size);
network->initialize();
networkLock = new NetworkLock(network, preferences, CharBuffer::get(), buffer_size);
networkLock = new NukiNetworkLock(network, preferences, CharBuffer::get(), buffer_size);
networkLock->initialize();
if(openerEnabled)
{
networkOpener = new NetworkOpener(network, preferences, CharBuffer::get(), buffer_size);
networkOpener = new NukiNetworkOpener(network, preferences, CharBuffer::get(), buffer_size);
networkOpener->initialize();
}
@@ -378,14 +528,24 @@ void setup()
if(preferences->getBool(preference_webserver_enabled, true))
{
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi);
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, gpio, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi, partitionType);
webCfgServer->initialize();
}
#endif
setupTasks();
if((partitionType==1 && preferences->getString(preference_ota_updater_url).length() > 0) || (partitionType==2 && preferences->getString(preference_ota_main_url).length() > 0)) setupTasks(true);
else setupTasks(false);
}
void loop()
{
vTaskDelete(NULL);
}
void printBeforeSetupInfo()
{
}
void printAfterSetupInfo()
{
}

View File

@@ -6,8 +6,10 @@
#include "EthLan8720Device.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
#ifndef NUKI_HUB_UPDATER
#include "../MqttTopics.h"
#include "espMqttClient.h"
#endif
#include "../RestartReason.h"
EthLan8720Device::EthLan8720Device(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, bool use_mac_from_efuse)
@@ -23,6 +25,7 @@ EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* preferen
{
_restartOnDisconnect = preferences->getBool(preference_restart_on_disconnect);
#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);
@@ -59,6 +62,7 @@ EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* preferen
strcpy(_path, pathStr.c_str());
Log = new MqttLogger(*getMqttClient(), _path, MqttLoggerMode::MqttAndSerial);
}
#endif
}
const String EthLan8720Device::deviceName() const
@@ -71,23 +75,29 @@ void EthLan8720Device::initialize()
delay(250);
WiFi.setHostname(_hostname.c_str());
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))
_hardwareInitialized = ETH.begin(_phy_addr, _power, _mdc, _mdio, _type, _clock_mode, _use_mac_from_efuse);
#else
#ifdef CONFIG_IDF_TARGET_ESP32
_hardwareInitialized = ETH.begin(_type, _phy_addr, _mdc, _mdio, ETH_RESET_PIN, _clock_mode);
#else
_hardwareInitialized = false;
#endif
#endif
ETH.setHostname(_hostname.c_str());
if(!_ipConfiguration->dhcpEnabled())
{
ETH.config(_ipConfiguration->ipAddress(), _ipConfiguration->defaultGateway(), _ipConfiguration->subnet(), _ipConfiguration->dnsServer());
}
if(_restartOnDisconnect)
WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info)
{
WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info)
if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
{
if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
{
onDisconnected();
}
});
}
onDisconnected();
}
});
}
void EthLan8720Device::reconfigure()
@@ -128,10 +138,8 @@ ReconnectStatus EthLan8720Device::reconnect()
void EthLan8720Device::onDisconnected()
{
if(millis() > 60000)
{
restartEsp(RestartReason::RestartOnDisconnectWatchdog);
}
if(_restartOnDisconnect && (millis() > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
reconnect();
}
int8_t EthLan8720Device::signalStrength()

View File

@@ -1,10 +1,38 @@
#pragma once
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(5, 0, 0))
#ifndef CONFIG_IDF_TARGET_ESP32
typedef enum {
ETH_CLOCK_GPIO0_IN = 0,
ETH_CLOCK_GPIO16_OUT = 2,
ETH_CLOCK_GPIO17_OUT = 3
} eth_clock_mode_t;
#define ETH_PHY_TYPE ETH_PHY_MAX
#else
#define ETH_PHY_TYPE ETH_PHY_LAN8720
#endif
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
#define ETH_PHY_ADDR 0
#define ETH_PHY_MDC 23
#define ETH_PHY_MDIO 18
#define ETH_PHY_POWER -1
#define ETH_RESET_PIN 1
#endif
#include <WiFiClient.h>
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))
#include <WiFiClientSecure.h>
#else
#include <NetworkClientSecure.h>
#endif
#include <Preferences.h>
#include "NetworkDevice.h"
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#endif
#include <ETH.h>
class EthLan8720Device : public NetworkDevice
@@ -54,8 +82,9 @@ private:
eth_phy_type_t _type;
eth_clock_mode_t _clock_mode;
bool _use_mac_from_efuse;
#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

@@ -8,6 +8,7 @@ void NetworkDevice::printError()
Log->println(ESP.getFreeHeap());
}
#ifndef NUKI_HUB_UPDATER
void NetworkDevice::update()
{
if (_mqttEnabled)
@@ -40,6 +41,18 @@ void NetworkDevice::mqttSetCleanSession(bool 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);
@@ -158,4 +171,9 @@ MqttClient *NetworkDevice::getMqttClient() const
{
return _mqttClient;
}
}
}
#else
void NetworkDevice::update()
{
}
#endif

View File

@@ -1,7 +1,9 @@
#pragma once
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#include "MqttClientSetup.h"
#endif
#include "IPConfiguration.h"
enum class ReconnectStatus
@@ -35,8 +37,10 @@ public:
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;
@@ -51,16 +55,19 @@ public:
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;
MqttClient *getMqttClient() const;
};

View File

@@ -3,7 +3,9 @@
#include "W5500Device.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
#ifndef NUKI_HUB_UPDATER
#include "../MqttTopics.h"
#endif
#include "sdkconfig.h"
W5500Device::W5500Device(const String &hostname, Preferences* preferences, const IPConfiguration* ipConfiguration, int variant)
@@ -27,8 +29,9 @@ W5500Device::W5500Device(const String &hostname, Preferences* preferences, const
}
}
Log->println();
#ifndef NUKI_HUB_UPDATER
_mqttClient = new espMqttClientW5500();
#endif
}
W5500Device::~W5500Device()
@@ -61,6 +64,7 @@ void W5500Device::initialize()
break;
}
#ifndef NUKI_HUB_UPDATER
if(_preferences->getBool(preference_mqtt_log_enabled))
{
String pathStr = _preferences->getString(preference_mqtt_lock_path);
@@ -70,6 +74,7 @@ void W5500Device::initialize()
strcpy(_path, pathStr.c_str());
Log = new MqttLogger(*getMqttClient(), _path, MqttLoggerMode::MqttAndSerial);
}
#endif
reconnect();
}

View File

@@ -1,8 +1,10 @@
#pragma once
#include "NetworkDevice.h"
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#include "espMqttClientW5500.h"
#endif
#include <Ethernet.h>
#include <Preferences.h>

View File

@@ -2,8 +2,10 @@
#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];
@@ -15,6 +17,7 @@ WifiDevice::WifiDevice(const String& hostname, Preferences* preferences, const I
{
_startAp = strcmp(WiFiDevice_reconfdetect, "reconfigure_wifi") == 0;
#ifndef NUKI_HUB_UPDATER
_restartOnDisconnect = preferences->getBool(preference_restart_on_disconnect);
size_t caLength = preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
@@ -53,6 +56,7 @@ WifiDevice::WifiDevice(const String& hostname, Preferences* preferences, const I
strcpy(_path, pathStr.c_str());
Log = new MqttLogger(*getMqttClient(), _path, MqttLoggerMode::MqttAndSerial);
}
#endif
}
const String WifiDevice::deviceName() const
@@ -94,9 +98,9 @@ void WifiDevice::initialize()
if(!res)
{
esp_wifi_disconnect ();
esp_wifi_stop ();
esp_wifi_deinit ();
esp_wifi_disconnect();
esp_wifi_stop();
esp_wifi_deinit();
Log->println(F("Failed to connect. Wait for ESP restart."));
delay(1000);
@@ -107,16 +111,17 @@ void WifiDevice::initialize()
Log->println(WiFi.localIP().toString());
}
if(_restartOnDisconnect)
WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info)
{
WiFi.onEvent([&](WiFiEvent_t event, WiFiEventInfo_t info)
if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
{
if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
{
onDisconnected();
}
});
}
onDisconnected();
}
else if(event == ARDUINO_EVENT_WIFI_STA_GOT_IP)
{
onConnected();
}
});
}
void WifiDevice::reconfigure()
@@ -138,16 +143,30 @@ bool WifiDevice::isConnected()
ReconnectStatus WifiDevice::reconnect()
{
delay(3000);
if(!isConnected() && !_isReconnecting)
{
_isReconnecting = true;
_wm.autoConnect();
delay(10000);
_isReconnecting = false;
}
if(!isConnected() && _disconnectTs > millis() - 120000) _wm.setEnableConfigPortal(_startAp || !_preferences->getBool(preference_network_wifi_fallback_disabled));
return isConnected() ? ReconnectStatus::Success : ReconnectStatus::Failure;
}
void WifiDevice::onConnected()
{
_isReconnecting = false;
_wm.setEnableConfigPortal(_startAp || !_preferences->getBool(preference_network_wifi_fallback_disabled));
}
void WifiDevice::onDisconnected()
{
if(millis() > 60000)
{
restartEsp(RestartReason::RestartOnDisconnectWatchdog);
}
_disconnectTs = millis();
if(_restartOnDisconnect && (millis() > 60000)) restartEsp(RestartReason::RestartOnDisconnectWatchdog);
_wm.setEnableConfigPortal(false);
reconnect();
}
int8_t WifiDevice::signalStrength()

View File

@@ -1,11 +1,17 @@
#pragma once
#include <WiFiClient.h>
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))
#include <WiFiClientSecure.h>
#else
#include <NetworkClientSecure.h>
#endif
#include <Preferences.h>
#include "NetworkDevice.h"
#include "WiFiManager.h"
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
#endif
#include "IPConfiguration.h"
class WifiDevice : public NetworkDevice
@@ -31,15 +37,20 @@ private:
static void clearRtcInitVar(WiFiManager*);
void onDisconnected();
void onConnected();
WiFiManager _wm;
Preferences* _preferences = nullptr;
bool _restartOnDisconnect = false;
bool _startAp = false;
bool _isReconnecting = false;
char* _path;
unsigned long _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
};