merge master
This commit is contained in:
@@ -43,6 +43,7 @@ include_directories(${PROJECT_NAME}
|
|||||||
set(SRCFILES
|
set(SRCFILES
|
||||||
Pins.h
|
Pins.h
|
||||||
Config.h
|
Config.h
|
||||||
|
CharBuffer.cpp
|
||||||
Network.cpp
|
Network.cpp
|
||||||
MqttReceiver.h
|
MqttReceiver.h
|
||||||
NetworkLock.cpp
|
NetworkLock.cpp
|
||||||
|
|||||||
13
CharBuffer.cpp
Normal file
13
CharBuffer.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include "CharBuffer.h"
|
||||||
|
|
||||||
|
void CharBuffer::initialize()
|
||||||
|
{
|
||||||
|
_buffer = new char[CHAR_BUFFER_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
char *CharBuffer::get()
|
||||||
|
{
|
||||||
|
return _buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* CharBuffer::_buffer;
|
||||||
13
CharBuffer.h
Normal file
13
CharBuffer.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CHAR_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
class CharBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void initialize();
|
||||||
|
static char* get();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static char* _buffer;
|
||||||
|
};
|
||||||
2
Config.h
2
Config.h
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define NUKI_HUB_VERSION "8.18-lilygo-1"
|
#define NUKI_HUB_VERSION "8.19-pre-3"
|
||||||
|
|
||||||
#define MQTT_QOS_LEVEL 1
|
#define MQTT_QOS_LEVEL 1
|
||||||
#define MQTT_CLEAN_SESSIONS false
|
#define MQTT_CLEAN_SESSIONS false
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define NUKI_HUB_VERSION "8.13"
|
|
||||||
|
|
||||||
#define MQTT_QOS_LEVEL 1
|
|
||||||
#define MQTT_CLEAN_SESSIONS false
|
|
||||||
@@ -36,10 +36,11 @@
|
|||||||
#define mqtt_topic_config_auto_lock "/configuration/autoLock"
|
#define mqtt_topic_config_auto_lock "/configuration/autoLock"
|
||||||
#define mqtt_topic_config_single_lock "/configuration/singleLock"
|
#define mqtt_topic_config_single_lock "/configuration/singleLock"
|
||||||
#define mqtt_topic_config_sound_level "/configuration/soundLevel"
|
#define mqtt_topic_config_sound_level "/configuration/soundLevel"
|
||||||
|
#define mqtt_topic_config_last_action_authorization "/configuration/lastActionAuthorizaton"
|
||||||
|
|
||||||
#define mqtt_topic_info_hardware_version "/info/hardwareVersion"
|
#define mqtt_topic_info_hardware_version "/info/hardwareVersion"
|
||||||
#define mqtt_topic_info_firmware_version "/info/firmwareVersion"
|
#define mqtt_topic_info_firmware_version "/info/firmwareVersion"
|
||||||
|
#define mqtt_topic_info_nuki_hub_version "/info/nukiHubVersion"
|
||||||
|
|
||||||
#define mqtt_topic_keypad "/keypad"
|
#define mqtt_topic_keypad "/keypad"
|
||||||
#define mqtt_topic_keypad_command_action "/keypad/command/action"
|
#define mqtt_topic_keypad_command_action "/keypad/command/action"
|
||||||
@@ -57,4 +58,5 @@
|
|||||||
#define mqtt_topic_log "/maintenance/log"
|
#define mqtt_topic_log "/maintenance/log"
|
||||||
#define mqtt_topic_freeheap "/maintenance/freeHeap"
|
#define mqtt_topic_freeheap "/maintenance/freeHeap"
|
||||||
#define mqtt_topic_restart_reason_fw "/maintenance/restartReasonNukiHub"
|
#define mqtt_topic_restart_reason_fw "/maintenance/restartReasonNukiHub"
|
||||||
#define mqtt_topic_restart_reason_esp "/maintenance/restartReasonNukiEsp"
|
#define mqtt_topic_restart_reason_esp "/maintenance/restartReasonNukiEsp"
|
||||||
|
#define mqtt_topic_network_device "/maintenance/networkDevice"
|
||||||
90
Network.cpp
90
Network.cpp
@@ -11,11 +11,14 @@
|
|||||||
|
|
||||||
Network* Network::_inst = nullptr;
|
Network* Network::_inst = nullptr;
|
||||||
unsigned long Network::_ignoreSubscriptionsTs = 0;
|
unsigned long Network::_ignoreSubscriptionsTs = 0;
|
||||||
|
bool _versionPublished = false;
|
||||||
|
|
||||||
RTC_NOINIT_ATTR char WiFi_fallbackDetect[14];
|
RTC_NOINIT_ATTR char WiFi_fallbackDetect[14];
|
||||||
|
|
||||||
Network::Network(Preferences *preferences, const String& maintenancePathPrefix)
|
Network::Network(Preferences *preferences, const String& maintenancePathPrefix, char* buffer, size_t bufferSize)
|
||||||
: _preferences(preferences)
|
: _preferences(preferences),
|
||||||
|
_buffer(buffer),
|
||||||
|
_bufferSize(bufferSize)
|
||||||
{
|
{
|
||||||
_inst = this;
|
_inst = this;
|
||||||
_hostname = _preferences->getString(preference_hostname);
|
_hostname = _preferences->getString(preference_hostname);
|
||||||
@@ -296,6 +299,10 @@ bool Network::update()
|
|||||||
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_fw, getRestartReason().c_str());
|
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_fw, getRestartReason().c_str());
|
||||||
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_esp, getEspRestartReason().c_str());
|
publishString(_maintenancePathPrefix, mqtt_topic_restart_reason_esp, getEspRestartReason().c_str());
|
||||||
}
|
}
|
||||||
|
if (!_versionPublished) {
|
||||||
|
publishString(_maintenancePathPrefix, mqtt_topic_info_nuki_hub_version, NUKI_HUB_VERSION);
|
||||||
|
_versionPublished = true;
|
||||||
|
}
|
||||||
_lastMaintenanceTs = ts;
|
_lastMaintenanceTs = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +410,7 @@ bool Network::reconnect()
|
|||||||
if(_firstConnect)
|
if(_firstConnect)
|
||||||
{
|
{
|
||||||
_firstConnect = false;
|
_firstConnect = false;
|
||||||
|
publishString(_maintenancePathPrefix, mqtt_topic_network_device, _device->deviceName().c_str());
|
||||||
for(const auto& it : _initTopics)
|
for(const auto& it : _initTopics)
|
||||||
{
|
{
|
||||||
_device->mqttPublish(it.first.c_str(), MQTT_QOS_LEVEL, true, it.second.c_str());
|
_device->mqttPublish(it.first.c_str(), MQTT_QOS_LEVEL, true, it.second.c_str());
|
||||||
@@ -585,7 +593,6 @@ void Network::publishHASSConfig(char* deviceType, const char* baseTopic, char* n
|
|||||||
|
|
||||||
if (discoveryTopic != "")
|
if (discoveryTopic != "")
|
||||||
{
|
{
|
||||||
char* jsonOut = new char[JSON_BUFFER_SIZE];
|
|
||||||
DynamicJsonDocument json(JSON_BUFFER_SIZE);
|
DynamicJsonDocument json(JSON_BUFFER_SIZE);
|
||||||
|
|
||||||
auto dev = json.createNestedObject("dev");
|
auto dev = json.createNestedObject("dev");
|
||||||
@@ -606,16 +613,14 @@ void Network::publishHASSConfig(char* deviceType, const char* baseTopic, char* n
|
|||||||
json["stat_unlocked"] = unlockedState;
|
json["stat_unlocked"] = unlockedState;
|
||||||
json["opt"] = "false";
|
json["opt"] = "false";
|
||||||
|
|
||||||
serializeJson(json, reinterpret_cast<char(&)[JSON_BUFFER_SIZE]>(*jsonOut));
|
serializeJson(json, _buffer, _bufferSize);
|
||||||
|
|
||||||
String path = discoveryTopic;
|
String path = discoveryTopic;
|
||||||
path.concat("/lock/");
|
path.concat("/lock/");
|
||||||
path.concat(uidString);
|
path.concat(uidString);
|
||||||
path.concat("/smartlock/config");
|
path.concat("/smartlock/config");
|
||||||
|
|
||||||
_device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, jsonOut);
|
_device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
|
||||||
|
|
||||||
delete jsonOut;
|
|
||||||
|
|
||||||
// Battery critical
|
// Battery critical
|
||||||
publishHassTopic("binary_sensor",
|
publishHassTopic("binary_sensor",
|
||||||
@@ -724,6 +729,23 @@ void Network::publishHASSConfig(char* deviceType, const char* baseTopic, char* n
|
|||||||
{ { "enabled_by_default", "true" },
|
{ { "enabled_by_default", "true" },
|
||||||
{"ic", "mdi:counter"}});
|
{"ic", "mdi:counter"}});
|
||||||
|
|
||||||
|
// NUKI Hub version
|
||||||
|
publishHassTopic("sensor",
|
||||||
|
"nuki_hub_version",
|
||||||
|
uidString,
|
||||||
|
"_nuki_hub__version",
|
||||||
|
"NUKI Hub version",
|
||||||
|
name,
|
||||||
|
baseTopic,
|
||||||
|
mqtt_topic_info_nuki_hub_version,
|
||||||
|
deviceType,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"diagnostic",
|
||||||
|
"",
|
||||||
|
{ { "enabled_by_default", "true" },
|
||||||
|
{"ic", "mdi:counter"}});
|
||||||
|
|
||||||
// LED enabled
|
// LED enabled
|
||||||
publishHassTopic("switch",
|
publishHassTopic("switch",
|
||||||
"led_enabled",
|
"led_enabled",
|
||||||
@@ -863,7 +885,7 @@ void Network::publishHASSConfigLedBrightness(char *deviceType, const char *baseT
|
|||||||
|
|
||||||
void Network::publishHASSConfigSoundLevel(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
void Network::publishHASSConfigSoundLevel(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
||||||
{
|
{
|
||||||
publishHassTopic("number",
|
publishHassTopic("sensor",
|
||||||
"sound_level",
|
"sound_level",
|
||||||
uidString,
|
uidString,
|
||||||
"_sound_level",
|
"_sound_level",
|
||||||
@@ -881,6 +903,45 @@ void Network::publishHASSConfigSoundLevel(char *deviceType, const char *baseTopi
|
|||||||
{ "max", "255" }});
|
{ "max", "255" }});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Network::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
||||||
|
{
|
||||||
|
publishHassTopic("sensor",
|
||||||
|
"last_action_authorization",
|
||||||
|
uidString,
|
||||||
|
"_last_action_authorization",
|
||||||
|
"Last action authorization",
|
||||||
|
name,
|
||||||
|
baseTopic,
|
||||||
|
mqtt_topic_lock_log,
|
||||||
|
deviceType,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"diagnostic",
|
||||||
|
"",
|
||||||
|
{ { "ic", "mdi:format-list-bulleted" },
|
||||||
|
{ "value_template", "{{ (value_json|selectattr('type', 'eq', 'LockAction')|selectattr('action', 'in', ['Lock', 'Unlock', 'Unlatch'])|first).authorizationName }}" }});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::publishHASSConfigKeypadAttemptInfo(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
||||||
|
{
|
||||||
|
publishHassTopic("sensor",
|
||||||
|
"keypad_status",
|
||||||
|
uidString,
|
||||||
|
"_keypad_stats",
|
||||||
|
"Keypad status",
|
||||||
|
name,
|
||||||
|
baseTopic,
|
||||||
|
mqtt_topic_lock_log,
|
||||||
|
deviceType,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"diagnostic",
|
||||||
|
"",
|
||||||
|
{ { "ic", "mdi:drag-vertical" },
|
||||||
|
{ "value_template", "{{ (value_json|selectattr('type', 'eq', 'KeypadAction')|first).completionStatus }}" }});
|
||||||
|
}
|
||||||
|
|
||||||
void Network::publishHASSWifiRssiConfig(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
void Network::publishHASSWifiRssiConfig(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
||||||
{
|
{
|
||||||
if(_device->signalStrength() == 127)
|
if(_device->signalStrength() == 127)
|
||||||
@@ -952,8 +1013,7 @@ void Network::publishHassTopic(const String& mqttDeviceType,
|
|||||||
|
|
||||||
if (discoveryTopic != "")
|
if (discoveryTopic != "")
|
||||||
{
|
{
|
||||||
char *jsonOut = new char[JSON_BUFFER_SIZE];
|
DynamicJsonDocument json(_bufferSize);
|
||||||
DynamicJsonDocument json(JSON_BUFFER_SIZE);
|
|
||||||
|
|
||||||
// Battery level
|
// Battery level
|
||||||
json.clear();
|
json.clear();
|
||||||
@@ -990,7 +1050,7 @@ void Network::publishHassTopic(const String& mqttDeviceType,
|
|||||||
json[entry.first] = entry.second;
|
json[entry.first] = entry.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeJson(json, reinterpret_cast<char (&)[JSON_BUFFER_SIZE]>(*jsonOut));
|
serializeJson(json, _buffer, _bufferSize);
|
||||||
|
|
||||||
String path = discoveryTopic;
|
String path = discoveryTopic;
|
||||||
path.concat("/");
|
path.concat("/");
|
||||||
@@ -1001,9 +1061,7 @@ void Network::publishHassTopic(const String& mqttDeviceType,
|
|||||||
path.concat(mattDeviceName);
|
path.concat(mattDeviceName);
|
||||||
path.concat("/config");
|
path.concat("/config");
|
||||||
|
|
||||||
_device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, jsonOut);
|
_device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
|
||||||
|
|
||||||
delete jsonOut;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,9 +1148,9 @@ void Network::removeHASSConfig(char* uidString)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::removeHASSConfigDoorSensor(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
void Network::removeHASSConfigTopic(char *deviceType, char *name, char *uidString)
|
||||||
{
|
{
|
||||||
removeHassTopic("binary_sensor", "door_sensor", uidString);
|
removeHassTopic(deviceType, name, uidString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::publishPresenceDetection(char *csv)
|
void Network::publishPresenceDetection(char *csv)
|
||||||
|
|||||||
10
Network.h
10
Network.h
@@ -22,7 +22,7 @@ enum class NetworkDeviceType
|
|||||||
class Network
|
class Network
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Network(Preferences* preferences, const String& maintenancePathPrefix);
|
explicit Network(Preferences* preferences, const String& maintenancePathPrefix, char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
bool update();
|
bool update();
|
||||||
@@ -47,10 +47,12 @@ public:
|
|||||||
void publishHASSConfigRingDetect(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
void publishHASSConfigRingDetect(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
void publishHASSConfigLedBrightness(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
void publishHASSConfigLedBrightness(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
void publishHASSConfigSoundLevel(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
void publishHASSConfigSoundLevel(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
|
void publishHASSConfigAccessLog(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
|
void publishHASSConfigKeypadAttemptInfo(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
void publishHASSWifiRssiConfig(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
void publishHASSWifiRssiConfig(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
void publishHASSBleRssiConfig(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
void publishHASSBleRssiConfig(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||||
void removeHASSConfig(char* uidString);
|
void removeHASSConfig(char* uidString);
|
||||||
void removeHASSConfigDoorSensor(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
void removeHASSConfigTopic(char* deviceType, char* name, char* uidString);
|
||||||
|
|
||||||
void clearWifiFallback();
|
void clearWifiFallback();
|
||||||
|
|
||||||
@@ -126,6 +128,10 @@ private:
|
|||||||
bool _mqttEnabled = true;
|
bool _mqttEnabled = true;
|
||||||
static unsigned long _ignoreSubscriptionsTs;
|
static unsigned long _ignoreSubscriptionsTs;
|
||||||
long _rssiPublishInterval = 0;
|
long _rssiPublishInterval = 0;
|
||||||
|
|
||||||
|
char* _buffer;
|
||||||
|
const size_t _bufferSize;
|
||||||
|
|
||||||
std::function<void()> _keepAliveCallback = nullptr;
|
std::function<void()> _keepAliveCallback = nullptr;
|
||||||
std::vector<std::function<void()>> _reconnectedCallbacks;
|
std::vector<std::function<void()>> _reconnectedCallbacks;
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,13 @@
|
|||||||
#include "PreferencesKeys.h"
|
#include "PreferencesKeys.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "RestartReason.h"
|
#include "RestartReason.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
NetworkLock::NetworkLock(Network* network, Preferences* preferences)
|
NetworkLock::NetworkLock(Network* network, Preferences* preferences, char* buffer, size_t bufferSize)
|
||||||
: _network(network),
|
: _network(network),
|
||||||
_preferences(preferences)
|
_preferences(preferences),
|
||||||
|
_buffer(buffer),
|
||||||
|
_bufferSize(bufferSize)
|
||||||
{
|
{
|
||||||
_configTopics.reserve(5);
|
_configTopics.reserve(5);
|
||||||
_configTopics.push_back(mqtt_topic_config_button_enabled);
|
_configTopics.push_back(mqtt_topic_config_button_enabled);
|
||||||
@@ -273,7 +276,6 @@ void NetworkLock::publishBinaryState(NukiLock::LockState lockState)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>& logEntries)
|
void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>& logEntries)
|
||||||
{
|
{
|
||||||
char str[50];
|
char str[50];
|
||||||
@@ -283,7 +285,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
|||||||
char authName[33];
|
char authName[33];
|
||||||
memset(authName, 0, sizeof(authName));
|
memset(authName, 0, sizeof(authName));
|
||||||
|
|
||||||
String json = "[\n";
|
DynamicJsonDocument json(_bufferSize);
|
||||||
|
|
||||||
for(const auto& log : logEntries)
|
for(const auto& log : logEntries)
|
||||||
{
|
{
|
||||||
@@ -294,90 +296,75 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
|||||||
memcpy(authName, log.name, sizeof(log.name));
|
memcpy(authName, log.name, sizeof(log.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
json.concat("{\n");
|
auto entry = json.add();
|
||||||
|
|
||||||
json.concat("\"index\": "); json.concat(log.index); json.concat(",\n");
|
entry["index"] = log.index;
|
||||||
json.concat("\"authorizationId\": "); json.concat(log.authId); json.concat(",\n");
|
entry["authorizationId"] = log.authId;
|
||||||
|
entry["authorizationName"] = log.name;
|
||||||
memset(str, 0, sizeof(str));
|
entry["timeYear"] = log.timeStampYear;
|
||||||
memcpy(str, log.name, sizeof(log.name));
|
entry["timeMonth"] = log.timeStampMonth;
|
||||||
json.concat("\"authorizationName\": \""); json.concat(str); json.concat("\",\n");
|
entry["timeDay"] = log.timeStampDay;
|
||||||
|
entry["timeHour"] = log.timeStampHour;
|
||||||
json.concat("\"timeYear\": "); json.concat(log.timeStampYear); json.concat(",\n");
|
entry["timeMinute"] = log.timeStampMinute;
|
||||||
json.concat("\"timeMonth\": "); json.concat(log.timeStampMonth); json.concat(",\n");
|
entry["timeSecond"] = log.timeStampSecond;
|
||||||
json.concat("\"timeDay\": "); json.concat(log.timeStampDay); json.concat(",\n");
|
|
||||||
json.concat("\"timeHour\": "); json.concat(log.timeStampHour); json.concat(",\n");
|
|
||||||
json.concat("\"timeMinute\": "); json.concat(log.timeStampMinute); json.concat(",\n");
|
|
||||||
json.concat("\"timeSecond\": "); json.concat(log.timeStampSecond); json.concat(",\n");
|
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
loggingTypeToString(log.loggingType, str);
|
loggingTypeToString(log.loggingType, str);
|
||||||
json.concat("\"type\": \""); json.concat(str); json.concat("\",\n");
|
entry["type"] = str;
|
||||||
|
|
||||||
switch(log.loggingType)
|
switch(log.loggingType)
|
||||||
{
|
{
|
||||||
case NukiLock::LoggingType::LockAction:
|
case NukiLock::LoggingType::LockAction:
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
||||||
json.concat("\"action\": \""); json.concat(str); json.concat("\",\n");
|
entry["action"] = str;
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str);
|
NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str);
|
||||||
json.concat("\"trigger\": \""); json.concat(str); json.concat("\",\n");
|
entry["trigger"] = str;
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str);
|
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str);
|
||||||
json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\"\n");
|
entry["completionStatus"] = str;
|
||||||
break;
|
break;
|
||||||
case NukiLock::LoggingType::KeypadAction:
|
case NukiLock::LoggingType::KeypadAction:
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
||||||
json.concat("\"action\": \""); json.concat(str); json.concat("\",\n");
|
entry["action"] = str;
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str);
|
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str);
|
||||||
json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\"\n");
|
entry["completionStatus"] = str;
|
||||||
break;
|
break;
|
||||||
case NukiLock::LoggingType::DoorSensor:
|
case NukiLock::LoggingType::DoorSensor:
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
||||||
json.concat("\"action\": \"");
|
|
||||||
switch(log.data[0])
|
switch(log.data[0])
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
json.concat("DoorOpened");
|
entry["action"] = "DoorOpened";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
json.concat("DoorClosed");
|
entry["action"] = "DoorClosed";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
json.concat("SensorJammed");
|
entry["action"] = "SensorJammed";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
json.concat("Unknown");
|
entry["action"] = "Unknown";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
json.concat("\",\n");
|
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str);
|
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str);
|
||||||
json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\"\n");
|
entry["completionStatus"] = str;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
json.concat("}");
|
|
||||||
if(&log == &logEntries.back())
|
|
||||||
{
|
|
||||||
json.concat("\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
json.concat(",\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
json.concat("]");
|
serializeJson(json, _buffer, _bufferSize);
|
||||||
publishString(mqtt_topic_lock_log, json);
|
publishString(mqtt_topic_lock_log, _buffer);
|
||||||
|
|
||||||
if(authFound)
|
if(authFound)
|
||||||
{
|
{
|
||||||
@@ -515,7 +502,7 @@ bool NetworkLock::comparePrefixedPath(const char *fullPath, const char *subPath)
|
|||||||
return strcmp(fullPath, prefixedPath) == 0;
|
return strcmp(fullPath, prefixedPath) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, char *name, char *uidString, const bool& hasDoorSensor, const bool& hasKeypad, char *lockAction,
|
void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, char *name, char *uidString, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char *lockAction,
|
||||||
char *unlockAction, char *openAction, char *lockedState, char *unlockedState)
|
char *unlockAction, char *openAction, char *lockedState, char *unlockedState)
|
||||||
{
|
{
|
||||||
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, hasKeypad, lockAction, unlockAction, openAction, lockedState, unlockedState);
|
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, hasKeypad, lockAction, unlockAction, openAction, lockedState, unlockedState);
|
||||||
@@ -527,10 +514,28 @@ void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, cha
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_network->removeHASSConfigDoorSensor(deviceType, baseTopic, name, uidString);
|
_network->removeHASSConfigTopic("binary_sensor", "door_sensor", uidString);
|
||||||
}
|
}
|
||||||
_network->publishHASSWifiRssiConfig(deviceType, baseTopic, name, uidString);
|
_network->publishHASSWifiRssiConfig(deviceType, baseTopic, name, uidString);
|
||||||
_network->publishHASSBleRssiConfig(deviceType, baseTopic, name, uidString);
|
_network->publishHASSBleRssiConfig(deviceType, baseTopic, name, uidString);
|
||||||
|
|
||||||
|
if(publishAuthData)
|
||||||
|
{
|
||||||
|
_network->publishHASSConfigAccessLog(deviceType, baseTopic, name, uidString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->removeHASSConfigTopic("sensor", "last_action_authorization", uidString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasKeypad)
|
||||||
|
{
|
||||||
|
_network->publishHASSConfigKeypadAttemptInfo(deviceType, baseTopic, name, uidString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_network->removeHASSConfigTopic("sensor", "keypad_status", uidString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkLock::removeHASSConfig(char *uidString)
|
void NetworkLock::removeHASSConfig(char *uidString)
|
||||||
|
|||||||
@@ -11,10 +11,12 @@
|
|||||||
#include "Network.h"
|
#include "Network.h"
|
||||||
#include "QueryCommand.h"
|
#include "QueryCommand.h"
|
||||||
|
|
||||||
|
#define LOCK_LOG_JSON_BUFFER_SIZE 2048
|
||||||
|
|
||||||
class NetworkLock : public MqttReceiver
|
class NetworkLock : public MqttReceiver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NetworkLock(Network* network, Preferences* preferences);
|
explicit NetworkLock(Network* network, Preferences* preferences, char* buffer, size_t bufferSize);
|
||||||
virtual ~NetworkLock();
|
virtual ~NetworkLock();
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
@@ -31,7 +33,7 @@ public:
|
|||||||
void publishRssi(const int& rssi);
|
void publishRssi(const int& rssi);
|
||||||
void publishRetry(const std::string& message);
|
void publishRetry(const std::string& message);
|
||||||
void publishBleAddress(const std::string& address);
|
void publishBleAddress(const std::string& address);
|
||||||
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& hasDoorSensor, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction, char* lockedState, char* unlockedState);
|
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction, char* lockedState, char* unlockedState);
|
||||||
void removeHASSConfig(char* uidString);
|
void removeHASSConfig(char* uidString);
|
||||||
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
||||||
void publishKeypadCommandResult(const char* result);
|
void publishKeypadCommandResult(const char* result);
|
||||||
@@ -79,6 +81,9 @@ private:
|
|||||||
int _keypadCommandEnabled = 1;
|
int _keypadCommandEnabled = 1;
|
||||||
uint8_t _queryCommands = 0;
|
uint8_t _queryCommands = 0;
|
||||||
|
|
||||||
|
char* _buffer;
|
||||||
|
size_t _bufferSize;
|
||||||
|
|
||||||
bool (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
bool (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
||||||
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
|
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
|
||||||
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
#include "PreferencesKeys.h"
|
#include "PreferencesKeys.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
NetworkOpener::NetworkOpener(Network* network, Preferences* preferences)
|
NetworkOpener::NetworkOpener(Network* network, Preferences* preferences, char* buffer, size_t bufferSize)
|
||||||
: _preferences(preferences),
|
: _preferences(preferences),
|
||||||
_network(network)
|
_network(network),
|
||||||
|
_buffer(buffer),
|
||||||
|
_bufferSize(bufferSize)
|
||||||
{
|
{
|
||||||
_configTopics.reserve(5);
|
_configTopics.reserve(5);
|
||||||
_configTopics.push_back(mqtt_topic_config_button_enabled);
|
_configTopics.push_back(mqtt_topic_config_button_enabled);
|
||||||
@@ -268,130 +271,111 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
|||||||
char authName[33];
|
char authName[33];
|
||||||
memset(authName, 0, sizeof(authName));
|
memset(authName, 0, sizeof(authName));
|
||||||
|
|
||||||
String json = "[\n";
|
DynamicJsonDocument json(_bufferSize);
|
||||||
|
|
||||||
for(const auto& log : logEntries)
|
for(const auto& log : logEntries)
|
||||||
{
|
{
|
||||||
if((log.loggingType == NukiOpener::LoggingType::LockAction || log.loggingType == NukiOpener::LoggingType::KeypadAction || log.loggingType == NukiOpener::LoggingType::DoorbellRecognition) && ! authFound)
|
if((log.loggingType == NukiOpener::LoggingType::LockAction || log.loggingType == NukiOpener::LoggingType::KeypadAction) && ! authFound)
|
||||||
{
|
{
|
||||||
authFound = true;
|
authFound = true;
|
||||||
authId = log.authId;
|
authId = log.authId;
|
||||||
memcpy(authName, log.name, sizeof(log.name));
|
memcpy(authName, log.name, sizeof(log.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
json.concat("{\n");
|
auto entry = json.add();
|
||||||
|
|
||||||
json.concat("\"index\": "); json.concat(log.index); json.concat(",\n");
|
entry["index"] = log.index;
|
||||||
json.concat("\"authorizationId\": "); json.concat(log.authId); json.concat(",\n");
|
entry["authorizationId"] = log.authId;
|
||||||
|
entry["authorizationName"] = log.name;
|
||||||
memset(str, 0, sizeof(str));
|
entry["timeYear"] = log.timeStampYear;
|
||||||
memcpy(str, log.name, sizeof(log.name));
|
entry["timeMonth"] = log.timeStampMonth;
|
||||||
json.concat("\"authorizationName\": \""); json.concat(str); json.concat("\",\n");
|
entry["timeDay"] = log.timeStampDay;
|
||||||
|
entry["timeHour"] = log.timeStampHour;
|
||||||
json.concat("\"timeYear\": "); json.concat(log.timeStampYear); json.concat(",\n");
|
entry["timeMinute"] = log.timeStampMinute;
|
||||||
json.concat("\"timeMonth\": "); json.concat(log.timeStampMonth); json.concat(",\n");
|
entry["timeSecond"] = log.timeStampSecond;
|
||||||
json.concat("\"timeDay\": "); json.concat(log.timeStampDay); json.concat(",\n");
|
|
||||||
json.concat("\"timeHour\": "); json.concat(log.timeStampHour); json.concat(",\n");
|
|
||||||
json.concat("\"timeMinute\": "); json.concat(log.timeStampMinute); json.concat(",\n");
|
|
||||||
json.concat("\"timeSecond\": "); json.concat(log.timeStampSecond); json.concat(",\n");
|
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
loggingTypeToString(log.loggingType, str);
|
loggingTypeToString(log.loggingType, str);
|
||||||
json.concat("\"type\": \""); json.concat(str); json.concat("\",\n");
|
entry["type"] = str;
|
||||||
|
|
||||||
switch(log.loggingType)
|
switch(log.loggingType)
|
||||||
{
|
{
|
||||||
case NukiOpener::LoggingType::LockAction:
|
case NukiOpener::LoggingType::LockAction:
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
lockactionToString((NukiOpener::LockAction)log.data[0], str);
|
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
||||||
json.concat("\"action\": \""); json.concat(str); json.concat("\",\n");
|
entry["action"] = str;
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
triggerToString((NukiOpener::Trigger)log.data[1], str);
|
NukiLock::triggerToString((NukiLock::Trigger)log.data[1], str);
|
||||||
json.concat("\"trigger\": \""); json.concat(str); json.concat("\",\n");
|
entry["trigger"] = str;
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
logactionCompletionStatusToString(log.data[3], str);
|
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[3], str);
|
||||||
json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\"\n");
|
entry["completionStatus"] = str;
|
||||||
break;
|
break;
|
||||||
case NukiOpener::LoggingType::KeypadAction:
|
case NukiOpener::LoggingType::KeypadAction:
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
lockactionToString((NukiOpener::LockAction)log.data[0], str);
|
NukiLock::lockactionToString((NukiLock::LockAction)log.data[0], str);
|
||||||
json.concat("\"action\": \""); json.concat(str); json.concat("\",\n");
|
entry["action"] = str;
|
||||||
|
|
||||||
memset(str, 0, sizeof(str));
|
memset(str, 0, sizeof(str));
|
||||||
completionStatusToString((NukiOpener::CompletionStatus)log.data[2], str);
|
NukiLock::completionStatusToString((NukiLock::CompletionStatus)log.data[2], str);
|
||||||
json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\"\n");
|
entry["completionStatus"] = str;
|
||||||
break;
|
break;
|
||||||
case NukiOpener::LoggingType::DoorbellRecognition:
|
case NukiOpener::LoggingType::DoorbellRecognition:
|
||||||
json.concat("\"mode\": \"");
|
|
||||||
switch(log.data[0] & 3)
|
switch(log.data[0] & 3)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
json.concat("None");
|
entry["mode"] = "None";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
json.concat("RTO");
|
entry["mode"] = "RTO";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
json.concat("CM");
|
entry["mode"] = "CM";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
json.concat("Unknown");
|
entry["mode"] = "Unknown";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
json.concat("\",\n");
|
|
||||||
|
|
||||||
json.concat("\"source\": \"");
|
|
||||||
switch(log.data[1])
|
switch(log.data[1])
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
json.concat("Doorbell");
|
entry["source"] = "Doorbell";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
json.concat("Timecontrol");
|
entry["source"] = "Timecontrol";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
json.concat("App");
|
entry["source"] = "App";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
json.concat("Button");
|
entry["source"] = "Button";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
json.concat("Fob");
|
entry["source"] = "Fob";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
json.concat("Bridge");
|
entry["source"] = "Bridge";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
json.concat("Keypad");
|
entry["source"] = "Keypad";
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
json.concat("\",\n");
|
entry["source"] = "Unknown";
|
||||||
|
break; }
|
||||||
|
|
||||||
json.concat("\"geofence\": \""); json.concat(log.data[2] == 1 ? "active" : "inactive"); json.concat("\",\n");
|
entry["geofence"] = log.data[2] == 1 ? "active" : "inactive";
|
||||||
json.concat("\"doorbellSuppression\": \""); json.concat(log.data[3] == 1 ? "active" : "inactive"); json.concat("\",\n");
|
entry["doorbellSuppression"] = log.data[3] == 1 ? "active" : "inactive";
|
||||||
|
entry["completionStatus"] = str;
|
||||||
memset(str, 0, sizeof(str));
|
|
||||||
logactionCompletionStatusToString(log.data[5], str);
|
|
||||||
json.concat("\"completionStatus\": \""); json.concat(str); json.concat("\"\n");
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
json.concat("}");
|
|
||||||
if(&log == &logEntries.back())
|
|
||||||
{
|
|
||||||
json.concat("\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
json.concat(",\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
json.concat("]");
|
serializeJson(json, _buffer, _bufferSize);
|
||||||
publishString(mqtt_topic_lock_log, json);
|
publishString(mqtt_topic_lock_log, _buffer);
|
||||||
|
|
||||||
if(authFound)
|
if(authFound)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
class NetworkOpener : public MqttReceiver
|
class NetworkOpener : public MqttReceiver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NetworkOpener(Network* network, Preferences* preferences);
|
explicit NetworkOpener(Network* network, Preferences* preferences, char* buffer, size_t bufferSize);
|
||||||
virtual ~NetworkOpener() = default;
|
virtual ~NetworkOpener() = default;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
@@ -83,6 +83,9 @@ private:
|
|||||||
unsigned long _resetLockStateTs = 0;
|
unsigned long _resetLockStateTs = 0;
|
||||||
uint8_t _queryCommands = 0;
|
uint8_t _queryCommands = 0;
|
||||||
|
|
||||||
|
char* _buffer;
|
||||||
|
const size_t _bufferSize;
|
||||||
|
|
||||||
bool (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
bool (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
||||||
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
|
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
|
||||||
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
||||||
|
|||||||
@@ -646,7 +646,7 @@ void NukiOpenerWrapper::setupHASS()
|
|||||||
String baseTopic = _preferences->getString(preference_mqtt_opener_path);
|
String baseTopic = _preferences->getString(preference_mqtt_opener_path);
|
||||||
char uidString[20];
|
char uidString[20];
|
||||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||||
_network->publishHASSConfig("Opener",baseTopic.c_str(),(char*)_nukiConfig.name,uidString,"deactivateRTO","activateRTO","electricStrikeActuation","locked","unlocked");
|
_network->publishHASSConfig("Opener",baseTopic.c_str(),(char*)_nukiConfig.name,uidString, "deactivateRTO","activateRTO","electricStrikeActuation","locked","unlocked");
|
||||||
_hassSetupCompleted = true;
|
_hassSetupCompleted = true;
|
||||||
|
|
||||||
Log->println("HASS setup for opener completed.");
|
Log->println("HASS setup for opener completed.");
|
||||||
|
|||||||
@@ -661,7 +661,7 @@ void NukiWrapper::setupHASS()
|
|||||||
char uidString[20];
|
char uidString[20];
|
||||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||||
|
|
||||||
_network->publishHASSConfig("SmartLock", baseTopic.c_str(),(char*)_nukiConfig.name, uidString, hasDoorSensor(), _hasKeypad, "lock", "unlock", "unlatch", "locked", "unlocked");
|
_network->publishHASSConfig("SmartLock", baseTopic.c_str(),(char*)_nukiConfig.name, uidString, hasDoorSensor(), _hasKeypad, _publishAuthData,"lock", "unlock", "unlatch", "locked", "unlocked");
|
||||||
_hassSetupCompleted = true;
|
_hassSetupCompleted = true;
|
||||||
|
|
||||||
Log->println("HASS setup for lock completed.");
|
Log->println("HASS setup for lock completed.");
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
#include "PresenceDetection.h"
|
#include "PresenceDetection.h"
|
||||||
#include "PreferencesKeys.h"
|
#include "PreferencesKeys.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "CharBuffer.h"
|
||||||
|
|
||||||
PresenceDetection::PresenceDetection(Preferences* preferences, BleScanner::Scanner *bleScanner, Network* network)
|
PresenceDetection::PresenceDetection(Preferences* preferences, BleScanner::Scanner *bleScanner, Network* network, char* buffer, size_t bufferSize)
|
||||||
: _preferences(preferences),
|
: _preferences(preferences),
|
||||||
_bleScanner(bleScanner),
|
_bleScanner(bleScanner),
|
||||||
_network(network)
|
_network(network),
|
||||||
|
_csv(buffer),
|
||||||
|
_bufferSize(bufferSize)
|
||||||
{
|
{
|
||||||
_csv = new char[presence_detection_buffer_size];
|
|
||||||
|
|
||||||
_timeout = _preferences->getInt(preference_presence_detection_timeout) * 1000;
|
_timeout = _preferences->getInt(preference_presence_detection_timeout) * 1000;
|
||||||
if(_timeout == 0)
|
if(_timeout == 0)
|
||||||
{
|
{
|
||||||
@@ -41,7 +42,7 @@ void PresenceDetection::update()
|
|||||||
delay(3000);
|
delay(3000);
|
||||||
|
|
||||||
if(_timeout < 0) return;
|
if(_timeout < 0) return;
|
||||||
memset(_csv, 0, presence_detection_buffer_size);
|
memset(_csv, 0, _bufferSize);
|
||||||
|
|
||||||
if(_devices.size() == 0)
|
if(_devices.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -60,7 +61,7 @@ void PresenceDetection::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prevent csv buffer overflow
|
// Prevent csv buffer overflow
|
||||||
if(_csvIndex > presence_detection_buffer_size - (sizeof(it.second.name) + sizeof(it.second.address) + 10))
|
if(_csvIndex > _bufferSize - (sizeof(it.second.name) + sizeof(it.second.address) + 10))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,10 @@ struct PdDevice
|
|||||||
bool hasRssi = false;
|
bool hasRssi = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define presence_detection_buffer_size 4096
|
|
||||||
|
|
||||||
class PresenceDetection : public BleScanner::Subscriber
|
class PresenceDetection : public BleScanner::Subscriber
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PresenceDetection(Preferences* preferences, BleScanner::Scanner* bleScanner, Network* network);
|
PresenceDetection(Preferences* preferences, BleScanner::Scanner* bleScanner, Network* network, char* buffer, size_t bufferSize);
|
||||||
virtual ~PresenceDetection();
|
virtual ~PresenceDetection();
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
@@ -33,6 +31,7 @@ private:
|
|||||||
BleScanner::Scanner* _bleScanner;
|
BleScanner::Scanner* _bleScanner;
|
||||||
Network* _network;
|
Network* _network;
|
||||||
char* _csv = {0};
|
char* _csv = {0};
|
||||||
|
size_t _bufferSize = 0;
|
||||||
std::map<long long, PdDevice> _devices;
|
std::map<long long, PdDevice> _devices;
|
||||||
int _timeout = 20000;
|
int _timeout = 20000;
|
||||||
int _csvIndex = 0;
|
int _csvIndex = 0;
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -51,7 +51,7 @@ Note: It is possible to run NUKI Hub alongside a NUKI Bridge. This is not recomm
|
|||||||
## Support
|
## Support
|
||||||
|
|
||||||
If you haven't ordered your NUKI product yet, you can support me by using my referrer code when placing your order:<br>
|
If you haven't ordered your NUKI product yet, you can support me by using my referrer code when placing your order:<br>
|
||||||
REFPGVT4XJ5JW<br>
|
REFXQ847A4ZDG<br>
|
||||||
This will also give you a 30€ discount for your order.
|
This will also give you a 30€ discount for your order.
|
||||||
|
|
||||||
This project is free to use for everyone. However if you feel like donating, you can buy me a coffee at ko-fi.com:
|
This project is free to use for everyone. However if you feel like donating, you can buy me a coffee at ko-fi.com:
|
||||||
@@ -187,8 +187,11 @@ The Pin configuration is:<br>
|
|||||||
|
|
||||||
## Connecting via LAN (Optional)
|
## Connecting via LAN (Optional)
|
||||||
|
|
||||||
If you prefer to connect to the MQTT Broker via LAN instead of WiFi, you can use a Wiznet W5x00 Module (W5100, W5200, W5500 are supported).
|
If you prefer to connect to the MQTT Broker via LAN instead of WiFi, you either use one of the supported ESP32 modules (see about section above),
|
||||||
To connect, just wire the module and connect the LAN cable:
|
or wire a seperate Wiznet W5x00 Module (W5100, W5200, W5500 are supported). To use a supported module, flash the firmware, connect via Wifi and
|
||||||
|
select the correct network hardware in the MQTT and network settings section.<br>
|
||||||
|
|
||||||
|
To wire an external W5x00 module to the ESP, use this wiring scheme:<br>
|
||||||
|
|
||||||
- Connect W5x00 to ESP32 SPI0:<br>
|
- Connect W5x00 to ESP32 SPI0:<br>
|
||||||
W5x00 SCK to GPIO18<br>
|
W5x00 SCK to GPIO18<br>
|
||||||
@@ -199,10 +202,10 @@ W5x00 CS/SS to GPIO5
|
|||||||
W5x00 reset to GPIO33
|
W5x00 reset to GPIO33
|
||||||
- Last but not least, on the ESP32 bridge GPIO26 and GND. This let's the firmware know that a LAN Module is connected
|
- Last but not least, on the ESP32 bridge GPIO26 and GND. This let's the firmware know that a LAN Module is connected
|
||||||
|
|
||||||
Wifi is now disabled, and the module doesn't boot into WifiManager anymore.
|
Wifi is now disabled, and the module doesn't boot into WifiManager anymore.<br>
|
||||||
|
Note: Encrypted MQTT is only available for Wifi and LAN8720 modules, W5x00 modules don't support encryption
|
||||||
As an alternative to do the wiring yourself, you can use an [M5Stack Atom POE](https://docs.m5stack.com/en/atom/atom_poe).
|
(that leaves Olimex, WT32-ETH01 and M5Stack PoESP32 Unit if encryption is desired). If encryption is needed, Olimex
|
||||||
After flashing, go to MQTT and network settings and select the module under "Network hardware".
|
is the easiest option, since it has USB for flashing onboard.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
11
main.cpp
11
main.cpp
@@ -13,6 +13,7 @@
|
|||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "RestartReason.h"
|
#include "RestartReason.h"
|
||||||
|
#include "CharBuffer.h"
|
||||||
|
|
||||||
Network* network = nullptr;
|
Network* network = nullptr;
|
||||||
NetworkLock* networkLock = nullptr;
|
NetworkLock* networkLock = nullptr;
|
||||||
@@ -170,6 +171,8 @@ void setup()
|
|||||||
bool firstStart = initPreferences();
|
bool firstStart = initPreferences();
|
||||||
initializeRestartReason();
|
initializeRestartReason();
|
||||||
|
|
||||||
|
CharBuffer::initialize();
|
||||||
|
|
||||||
if(preferences->getInt(preference_restart_timer) > 0)
|
if(preferences->getInt(preference_restart_timer) > 0)
|
||||||
{
|
{
|
||||||
restartTs = preferences->getInt(preference_restart_timer) * 60 * 1000;
|
restartTs = preferences->getInt(preference_restart_timer) * 60 * 1000;
|
||||||
@@ -179,15 +182,15 @@ void setup()
|
|||||||
openerEnabled = preferences->getBool(preference_opener_enabled);
|
openerEnabled = preferences->getBool(preference_opener_enabled);
|
||||||
|
|
||||||
const String mqttLockPath = preferences->getString(preference_mqtt_lock_path);
|
const String mqttLockPath = preferences->getString(preference_mqtt_lock_path);
|
||||||
network = new Network(preferences, mqttLockPath);
|
network = new Network(preferences, mqttLockPath, CharBuffer::get(), CHAR_BUFFER_SIZE);
|
||||||
network->initialize();
|
network->initialize();
|
||||||
|
|
||||||
networkLock = new NetworkLock(network, preferences);
|
networkLock = new NetworkLock(network, preferences, CharBuffer::get(), CHAR_BUFFER_SIZE);
|
||||||
networkLock->initialize();
|
networkLock->initialize();
|
||||||
|
|
||||||
if(openerEnabled)
|
if(openerEnabled)
|
||||||
{
|
{
|
||||||
networkOpener = new NetworkOpener(network, preferences);
|
networkOpener = new NetworkOpener(network, preferences, CharBuffer::get(), CHAR_BUFFER_SIZE);
|
||||||
networkOpener->initialize();
|
networkOpener->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +229,7 @@ void setup()
|
|||||||
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi);
|
webCfgServer = new WebCfgServer(nuki, nukiOpener, network, ethServer, preferences, network->networkDeviceType() == NetworkDeviceType::WiFi);
|
||||||
webCfgServer->initialize();
|
webCfgServer->initialize();
|
||||||
|
|
||||||
presenceDetection = new PresenceDetection(preferences, bleScanner, network);
|
presenceDetection = new PresenceDetection(preferences, bleScanner, network, CharBuffer::get(), CHAR_BUFFER_SIZE);
|
||||||
presenceDetection->initialize();
|
presenceDetection->initialize();
|
||||||
|
|
||||||
setupTasks();
|
setupTasks();
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ ReconnectStatus W5500Device::reconnect()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
hardwareFound = true;
|
||||||
_hasDHCPAddress = true;
|
_hasDHCPAddress = true;
|
||||||
dhcpRetryCnt = 1000;
|
dhcpRetryCnt = 1000;
|
||||||
if(_ipConfiguration->dhcpEnabled())
|
if(_ipConfiguration->dhcpEnabled())
|
||||||
|
|||||||
Reference in New Issue
Block a user