Publish keypad code and rolling log
This commit is contained in:
13
README.md
13
README.md
@@ -156,7 +156,8 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
### Access Level Configuration
|
||||
|
||||
#### Nuki General Access Control
|
||||
- Publish keypad codes information (Only available when a Keypad is detected): Enable to publish information about keypad codes through MQTT, see the "[Keypad control](#keypad-control-optional)" section of this README
|
||||
- Publish keypad entries information (Only available when a Keypad is detected): Enable to publish information about keypad codes through MQTT, see the "[Keypad control](#keypad-control-optional)" section of this README
|
||||
- Also publish keypad codes (Only available when a Keypad is detected): Enable to publish the actual keypad codes through MQTT, note that is could be considered a security risk
|
||||
- Add, modify and delete keypad codes (Only available when a Keypad is detected): Enable to allow configuration of keypad codes through MQTT, see the "[Keypad control](#keypad-control-optional)" section of this README
|
||||
- Publish time control information: Enable to publish information about time control entries through MQTT, see the "[Time Control](#time-control)" section of this README
|
||||
- Add, modify and delete time control entries: Enable to allow configuration of time control entries through MQTT, see the "[Time Control](#time-control)" section of this README
|
||||
@@ -204,8 +205,9 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
- lock/binaryState: Reports the current lock state as a string, mostly for use by Home Assistant. Possible values are: locked, unlocked.
|
||||
- lock/trigger: The trigger of the last action: autoLock, automatic, button, manual, system.
|
||||
- lock/lastLockAction: Reports the last lock action as a string. Possible values are: Unlock, Lock, Unlatch, LockNgo, LockNgoUnlatch, FullLock, FobAction1, FobAction2, FobAction3, Unknown.
|
||||
- lock/log: If "Publish auth data" is enabled in the web interface, this topic will be filled with the log of authorization data.
|
||||
- lock/log: If "Publish auth data" is enabled in the web interface, this topic will be filled with the log of authorization data. By default a maximum of 5 logs are published at a time.
|
||||
- lock/shortLog: If "Publish auth data" is enabled in the web interface, this topic will be filled with the 3 most recent entries in the log of authorization data, updates faster than lock/log.
|
||||
- lock/rollingLog: If "Publish auth data" is enabled in the web interface, this topic will be filled with the last log entry from the authorization data. Logs are published in order.
|
||||
- lock/completionStatus: Status of the last action as reported by Nuki Lock: success, motorBlocked, canceled, tooRecent, busy, lowMotorVoltage, clutchFailure, motorPowerFailure, incompleteFailure, invalidCode, otherError, unknown.
|
||||
- lock/authorizationId: If enabled in the web interface, this node returns the authorization id of the last lock action.
|
||||
- lock/authorizationName: If enabled in the web interface, this node returns the authorization name of the last lock action.
|
||||
@@ -465,7 +467,8 @@ If a keypad is connected to the lock, keypad codes can be added, updated and rem
|
||||
|
||||
Information about current keypad codes is published as JSON data to the "keypad/json" MQTT topic.<br>
|
||||
This needs to be enabled separately by checking "Publish keypad codes information" under "Access Level Configuration" and saving the configuration.
|
||||
For security reasons, the code itself is not published.
|
||||
For security reasons, the code itself is not published, unless this is explicitly enabled in the Nuki Hub settings.
|
||||
By default a maximum of 10 entries are published.
|
||||
|
||||
To change Nuki Lock/Opener keypad settings set the `keypad/actionJson` topic to a JSON formatted value containing the following nodes.
|
||||
|
||||
@@ -499,8 +502,9 @@ If a keypad is connected to the lock, keypad codes can be added, updated and rem
|
||||
This has to enabled first in the configuration portal. Check "Add, modify and delete keypad codes" under "Access Level Configuration" and save the configuration.
|
||||
|
||||
Information about codes is published under "keypad/code_x", x starting from 0 up the number of configured codes. This needs to be enabled separately by checking "Publish keypad codes information" under "Access Level Configuration" and saving the configuration.
|
||||
By default a maximum of 10 entries are published.
|
||||
|
||||
For security reasons, the code itself is not published. To modify keypad codes, a command
|
||||
For security reasons, the code itself is not published, unless this is explicitly enabled in the Nuki Hub settings. To modify keypad codes, a command
|
||||
structure is setup under keypad/command:
|
||||
|
||||
- keypad/command/id: The id of an existing code, found under keypad_code_x
|
||||
@@ -533,6 +537,7 @@ Time control entries can be added, updated and removed. This has to enabled firs
|
||||
|
||||
Information about current time control entries is published as JSON data to the "timecontrol/json" MQTT topic.<br>
|
||||
This needs to be enabled separately by checking "Publish time control entries information" under "Access Level Configuration" and saving the configuration.
|
||||
By default a maximum of 10 entries are published.
|
||||
|
||||
To change Nuki Lock/Opener time control settings set the `timecontrol/actionJson` topic to a JSON formatted value containing the following nodes.
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
@@ -1,46 +0,0 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "BleScanner",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Generic BleScanner using NimBle listening to advertisements. Used by NukiBleEsp32 and EnOcean libraries",
|
||||
"keywords": "ble esp32 scanner",
|
||||
"authors": [
|
||||
@@ -19,7 +19,7 @@
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "NimBLE-Arduino",
|
||||
"version": "h2zero/NimBLE-Arduino @ ^1.3.8"
|
||||
"version": "h2zero/NimBLE-Arduino @ ^1.4.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -4,4 +4,4 @@ board = esp32dev
|
||||
framework = arduino
|
||||
|
||||
lib_deps =
|
||||
h2zero/NimBLE-Arduino @ ^1.3.8
|
||||
h2zero/NimBLE-Arduino @ ^1.4.0
|
||||
@@ -22,11 +22,14 @@ Scanner::Scanner(int reservedSubscribers) {
|
||||
|
||||
void Scanner::initialize(const std::string& deviceName, const bool wantDuplicates, const uint16_t interval, const uint16_t window) {
|
||||
if (!BLEDevice::getInitialized()) {
|
||||
if (wantDuplicates) {
|
||||
// reduce memory footprint, cache is not used anyway
|
||||
NimBLEDevice::setScanDuplicateCacheSize(10);
|
||||
}
|
||||
BLEDevice::init(deviceName);
|
||||
}
|
||||
bleScan = BLEDevice::getScan();
|
||||
bleScan->setAdvertisedDeviceCallbacks(this, wantDuplicates);
|
||||
bleScan->setActiveScan(true);
|
||||
bleScan->setInterval(interval);
|
||||
bleScan->setWindow(window);
|
||||
}
|
||||
@@ -36,15 +39,20 @@ void Scanner::update() {
|
||||
return;
|
||||
}
|
||||
|
||||
bleScan->clearResults();
|
||||
if (scanDuration == 0) {
|
||||
// Avoid unbridled growth of results vector
|
||||
bleScan->setMaxResults(0);
|
||||
} else {
|
||||
log_w("Ble scanner max results not 0. Be aware of memory issue due to unbridled growth of results vector");
|
||||
}
|
||||
|
||||
bool result = bleScan->start(scanDuration, nullptr, false);
|
||||
if (!result) {
|
||||
scanErrors++;
|
||||
if (scanErrors % 100 == 0) {
|
||||
log_w("BLE Scan error (100x)");
|
||||
}
|
||||
}
|
||||
// if (!result) {
|
||||
// scanErrors++;
|
||||
// if (scanErrors % 100 == 0) {
|
||||
// log_w("BLE Scan error (100x)");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void Scanner::enableScanning(bool enable) {
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#include <NimBLEDevice.h>
|
||||
#include "BleInterfaces.h"
|
||||
|
||||
// Access to a globally available instance of BleScanner, created when first used
|
||||
// Note that BLESCANNER.initialize() has to be called somewhere
|
||||
#define BLESCANNER BleScanner::Scanner::instance()
|
||||
|
||||
namespace BleScanner {
|
||||
|
||||
class Scanner : public Publisher, BLEAdvertisedDeviceCallbacks {
|
||||
@@ -23,6 +27,11 @@ class Scanner : public Publisher, BLEAdvertisedDeviceCallbacks {
|
||||
Scanner(int reservedSubscribers = 10);
|
||||
~Scanner() = default;
|
||||
|
||||
static Scanner& instance() {
|
||||
static Scanner* scanner = new Scanner(); // only initialized once on first call
|
||||
return *scanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the BLE scanner
|
||||
*
|
||||
@@ -77,7 +86,7 @@ class Scanner : public Publisher, BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(NimBLEAdvertisedDevice* advertisedDevice) override;
|
||||
|
||||
private:
|
||||
uint32_t scanDuration = 3;
|
||||
uint32_t scanDuration = 0; //default indefinite scanning time
|
||||
BLEScan* bleScan = nullptr;
|
||||
std::vector<Subscriber*> subscribers;
|
||||
uint16_t scanErrors = 0;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#define mqtt_topic_lock_last_lock_action "/lock/lastLockAction"
|
||||
#define mqtt_topic_lock_log "/lock/log"
|
||||
#define mqtt_topic_lock_log_latest "/lock/shortLog"
|
||||
#define mqtt_topic_lock_log_rolling "/lock/rollingLog"
|
||||
#define mqtt_topic_lock_log_rolling_last "lock/lastRollingLog"
|
||||
#define mqtt_topic_lock_auth_id "/lock/authorizationId"
|
||||
#define mqtt_topic_lock_auth_name "/lock/authorizationName"
|
||||
#define mqtt_topic_lock_completionStatus "/lock/completionStatus"
|
||||
|
||||
@@ -3023,6 +3023,27 @@ void Network::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic
|
||||
"",
|
||||
{ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
|
||||
{ (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'LockAction')|selectattr('action', 'in', ['Lock', 'Unlock', 'Unlatch'])|first|default).authorizationName|default }}" }});
|
||||
|
||||
String rollingSate = "~";
|
||||
rollingSate.concat(mqtt_topic_lock_log_rolling);
|
||||
const char *rollingStateChr = rollingSate.c_str();
|
||||
|
||||
publishHassTopic("sensor",
|
||||
"rolling_log",
|
||||
uidString,
|
||||
"_rolling_log",
|
||||
"Rolling authorization log",
|
||||
name,
|
||||
baseTopic,
|
||||
String("~") + mqtt_topic_lock_log_rolling,
|
||||
deviceType,
|
||||
"",
|
||||
"",
|
||||
"diagnostic",
|
||||
"",
|
||||
{ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
|
||||
{ (char*)"json_attr_t", (char*)rollingStateChr },
|
||||
{ (char*)"val_tpl", (char*)"{{value_json.authorizationId}}" }});
|
||||
}
|
||||
|
||||
void Network::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, char *name, char *uidString)
|
||||
@@ -3194,6 +3215,7 @@ void Network::removeHASSConfig(char* uidString)
|
||||
removeHassTopic((char*)"sensor", (char*)"sound_level", uidString);
|
||||
removeHassTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
|
||||
removeHassTopic((char*)"sensor", (char*)"keypad_status", uidString);
|
||||
removeHassTopic((char*)"sensor", (char*)"rolling_log", uidString);
|
||||
removeHassTopic((char*)"sensor", (char*)"wifi_signal_strength", uidString);
|
||||
removeHassTopic((char*)"sensor", (char*)"bluetooth_signal_strength", uidString);
|
||||
removeHassTopic((char*)"binary_sensor", (char*)"continuous_mode", uidString);
|
||||
|
||||
@@ -116,6 +116,11 @@ void NetworkLock::initialize()
|
||||
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
|
||||
}
|
||||
|
||||
if(_preferences->getBool(preference_publish_authdata, false))
|
||||
{
|
||||
_network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last);
|
||||
}
|
||||
|
||||
_network->addReconnectedCallback([&]()
|
||||
{
|
||||
_reconnected = true;
|
||||
@@ -157,6 +162,13 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
|
||||
delay(200);
|
||||
restartEsp(RestartReason::RequestedViaMqtt);
|
||||
}
|
||||
else if(comparePrefixedPath(topic, mqtt_topic_lock_log_rolling_last))
|
||||
{
|
||||
if(strcmp(value, "") == 0 ||
|
||||
strcmp(value, "--") == 0) return;
|
||||
|
||||
if(atoi(value) > 0 && atoi(value) > _lastRollingLog) _lastRollingLog = atoi(value);
|
||||
}
|
||||
|
||||
if(comparePrefixedPath(topic, mqtt_topic_lock_action))
|
||||
{
|
||||
@@ -439,7 +451,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
{
|
||||
char str[50];
|
||||
char authName[33];
|
||||
bool authFound = false;
|
||||
uint32_t authIndex = 0;
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
@@ -454,9 +466,9 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
memcpy(authName, log.name, sizeName);
|
||||
if(authName[sizeName - 1] != '\0') authName[sizeName] = '\0';
|
||||
|
||||
if(!authFound)
|
||||
if(log.index > authIndex)
|
||||
{
|
||||
authFound = true;
|
||||
authIndex = log.index;
|
||||
_authFound = true;
|
||||
_authId = log.authId;
|
||||
memset(_authName, 0, sizeof(_authName));
|
||||
@@ -531,6 +543,14 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
entry["completionStatus"] = str;
|
||||
break;
|
||||
}
|
||||
|
||||
if(log.index > _lastRollingLog)
|
||||
{
|
||||
_lastRollingLog = log.index;
|
||||
serializeJson(entry, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_lock_log_rolling, _buffer);
|
||||
publishInt(mqtt_topic_lock_log_rolling_last, log.index);
|
||||
}
|
||||
}
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
@@ -538,7 +558,7 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer);
|
||||
else publishString(mqtt_topic_lock_log, _buffer);
|
||||
|
||||
if(authFound)
|
||||
if(authIndex > 0)
|
||||
{
|
||||
publishUInt(mqtt_topic_lock_auth_id, _authId);
|
||||
publishString(mqtt_topic_lock_auth_name, _authName);
|
||||
@@ -735,6 +755,12 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
|
||||
auto jsonEntry = json.add<JsonVariant>();
|
||||
|
||||
jsonEntry["codeId"] = entry.codeId;
|
||||
|
||||
if(_preferences->getBool(preference_keypad_publish_code, false))
|
||||
{
|
||||
jsonEntry["code"] = entry.code;
|
||||
}
|
||||
|
||||
jsonEntry["enabled"] = entry.enabled;
|
||||
jsonEntry["name"] = entry.name;
|
||||
char createdDT[20];
|
||||
@@ -826,6 +852,19 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if(!_preferences->getBool(preference_keypad_publish_code, false))
|
||||
{
|
||||
for(int i=0; i<maxKeypadCodeCount; i++)
|
||||
{
|
||||
String codeTopic = _mqttPath;
|
||||
codeTopic.concat(mqtt_topic_keypad);
|
||||
codeTopic.concat("/code_");
|
||||
codeTopic.concat(std::to_string(i).c_str());
|
||||
codeTopic.concat("/");
|
||||
_network->removeTopic(codeTopic, "code");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (maxKeypadCodeCount > 0)
|
||||
{
|
||||
@@ -838,6 +877,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
|
||||
codeTopic.concat("/");
|
||||
_network->removeTopic(codeTopic, "id");
|
||||
_network->removeTopic(codeTopic, "enabled");
|
||||
_network->removeTopic(codeTopic, "code");
|
||||
_network->removeTopic(codeTopic, "name");
|
||||
_network->removeTopic(codeTopic, "createdYear");
|
||||
_network->removeTopic(codeTopic, "createdMonth");
|
||||
@@ -1028,6 +1068,7 @@ void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, cha
|
||||
else
|
||||
{
|
||||
_network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
|
||||
_network->removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
|
||||
}
|
||||
|
||||
if(hasKeypad)
|
||||
@@ -1098,6 +1139,12 @@ void NetworkLock::publishKeypadEntry(const String topic, NukiLock::KeypadEntry e
|
||||
publishInt(concat(topic, "/id").c_str(), entry.codeId);
|
||||
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
|
||||
publishString(concat(topic, "/name").c_str(), codeName);
|
||||
|
||||
if(_preferences->getBool(preference_keypad_publish_code, false))
|
||||
{
|
||||
publishInt(concat(topic, "/code").c_str(), entry.code);
|
||||
}
|
||||
|
||||
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
|
||||
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
|
||||
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);
|
||||
|
||||
@@ -92,6 +92,7 @@ private:
|
||||
uint32_t _authId = 0;
|
||||
char _authName[33];
|
||||
bool _authFound = false;
|
||||
uint32_t _lastRollingLog = 0;
|
||||
|
||||
char* _buffer;
|
||||
size_t _bufferSize;
|
||||
|
||||
@@ -97,6 +97,11 @@ void NetworkOpener::initialize()
|
||||
_network->initTopic(_mqttPath, mqtt_topic_timecontrol_action, "--");
|
||||
}
|
||||
|
||||
if(_preferences->getBool(preference_publish_authdata, false))
|
||||
{
|
||||
_network->subscribe(_mqttPath, mqtt_topic_lock_log_rolling_last);
|
||||
}
|
||||
|
||||
_network->addReconnectedCallback([&]()
|
||||
{
|
||||
_reconnected = true;
|
||||
@@ -116,6 +121,14 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
|
||||
{
|
||||
char* value = (char*)payload;
|
||||
|
||||
if(comparePrefixedPath(topic, mqtt_topic_lock_log_rolling_last))
|
||||
{
|
||||
if(strcmp(value, "") == 0 ||
|
||||
strcmp(value, "--") == 0) return;
|
||||
|
||||
if(atoi(value) > 0 && atoi(value) > _lastRollingLog) _lastRollingLog = atoi(value);
|
||||
}
|
||||
|
||||
if(comparePrefixedPath(topic, mqtt_topic_lock_action))
|
||||
{
|
||||
if(strcmp(value, "") == 0 ||
|
||||
@@ -406,7 +419,7 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
{
|
||||
char str[50];
|
||||
char authName[33];
|
||||
bool authFound = false;
|
||||
uint32_t authIndex = 0;
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
@@ -421,9 +434,9 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
memcpy(authName, log.name, sizeName);
|
||||
if(authName[sizeName - 1] != '\0') authName[sizeName] = '\0';
|
||||
|
||||
if(!authFound)
|
||||
if(log.index > authIndex)
|
||||
{
|
||||
authFound = true;
|
||||
authIndex = log.index;
|
||||
_authFound = true;
|
||||
_authId = log.authId;
|
||||
memset(_authName, 0, sizeof(_authName));
|
||||
@@ -521,6 +534,14 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(log.index > _lastRollingLog)
|
||||
{
|
||||
_lastRollingLog = log.index;
|
||||
serializeJson(entry, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_lock_log_rolling, _buffer);
|
||||
publishInt(mqtt_topic_lock_log_rolling_last, log.index);
|
||||
}
|
||||
}
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
@@ -528,7 +549,7 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
if(latest) publishString(mqtt_topic_lock_log_latest, _buffer);
|
||||
else publishString(mqtt_topic_lock_log, _buffer);
|
||||
|
||||
if(authFound)
|
||||
if(authIndex > 0)
|
||||
{
|
||||
publishUInt(mqtt_topic_lock_auth_id, _authId);
|
||||
publishString(mqtt_topic_lock_auth_name, _authName);
|
||||
@@ -702,13 +723,23 @@ void NetworkOpener::publishBleAddress(const std::string &address)
|
||||
publishString(mqtt_topic_lock_address, address);
|
||||
}
|
||||
|
||||
void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, char* lockAction, char* unlockAction, char* openAction)
|
||||
void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction)
|
||||
{
|
||||
String availabilityTopic = _preferences->getString("mqttpath");
|
||||
availabilityTopic.concat("/maintenance/mqttConnectionState");
|
||||
|
||||
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, availabilityTopic.c_str(), false, lockAction, unlockAction, openAction);
|
||||
_network->publishHASSConfigAdditionalOpenerEntities(deviceType, baseTopic, name, uidString);
|
||||
|
||||
if(publishAuthData)
|
||||
{
|
||||
_network->publishHASSConfigAccessLog(deviceType, baseTopic, name, uidString);
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
|
||||
_network->removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOpener::removeHASSConfig(char* uidString)
|
||||
@@ -734,6 +765,12 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
|
||||
jsonEntry["codeId"] = entry.codeId;
|
||||
jsonEntry["enabled"] = entry.enabled;
|
||||
jsonEntry["name"] = entry.name;
|
||||
|
||||
if(_preferences->getBool(preference_keypad_publish_code, false))
|
||||
{
|
||||
jsonEntry["code"] = entry.code;
|
||||
}
|
||||
|
||||
char createdDT[20];
|
||||
sprintf(createdDT, "%04d-%02d-%02d %02d:%02d:%02d", entry.dateCreatedYear, entry.dateCreatedMonth, entry.dateCreatedDay, entry.dateCreatedHour, entry.dateCreatedMin, entry.dateCreatedSec);
|
||||
jsonEntry["dateCreated"] = createdDT;
|
||||
@@ -823,6 +860,19 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if(!_preferences->getBool(preference_keypad_publish_code, false))
|
||||
{
|
||||
for(int i=0; i<maxKeypadCodeCount; i++)
|
||||
{
|
||||
String codeTopic = _mqttPath;
|
||||
codeTopic.concat(mqtt_topic_keypad);
|
||||
codeTopic.concat("/code_");
|
||||
codeTopic.concat(std::to_string(i).c_str());
|
||||
codeTopic.concat("/");
|
||||
_network->removeTopic(codeTopic, "code");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (maxKeypadCodeCount > 0)
|
||||
{
|
||||
@@ -835,6 +885,7 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
|
||||
codeTopic.concat("/");
|
||||
_network->removeTopic(codeTopic, "id");
|
||||
_network->removeTopic(codeTopic, "enabled");
|
||||
_network->removeTopic(codeTopic, "code");
|
||||
_network->removeTopic(codeTopic, "name");
|
||||
_network->removeTopic(codeTopic, "createdYear");
|
||||
_network->removeTopic(codeTopic, "createdMonth");
|
||||
@@ -1025,6 +1076,12 @@ void NetworkOpener::publishKeypadEntry(const String topic, NukiLock::KeypadEntry
|
||||
publishInt(concat(topic, "/id").c_str(), entry.codeId);
|
||||
publishBool(concat(topic, "/enabled").c_str(), entry.enabled);
|
||||
publishString(concat(topic, "/name").c_str(), codeName);
|
||||
|
||||
if(_preferences->getBool(preference_keypad_publish_code, false))
|
||||
{
|
||||
publishInt(concat(topic, "/code").c_str(), entry.code);
|
||||
}
|
||||
|
||||
publishInt(concat(topic, "/createdYear").c_str(), entry.dateCreatedYear);
|
||||
publishInt(concat(topic, "/createdMonth").c_str(), entry.dateCreatedMonth);
|
||||
publishInt(concat(topic, "/createdDay").c_str(), entry.dateCreatedDay);
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
void publishRssi(const int& rssi);
|
||||
void publishRetry(const std::string& message);
|
||||
void publishBleAddress(const std::string& address);
|
||||
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, char* lockAction, char* unlockAction, char* openAction);
|
||||
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction);
|
||||
void removeHASSConfig(char* uidString);
|
||||
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
||||
void publishTimeControl(const std::list<NukiOpener::TimeControlEntry>& timeControlEntries);
|
||||
@@ -93,6 +93,7 @@ private:
|
||||
uint32_t _authId = 0;
|
||||
char _authName[33];
|
||||
bool _authFound = false;
|
||||
uint32_t _lastRollingLog = 0;
|
||||
|
||||
NukiOpener::LockState _currentLockState = NukiOpener::LockState::Undefined;
|
||||
|
||||
|
||||
@@ -521,6 +521,8 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
|
||||
log.resize(_preferences->getInt(preference_authlog_max_entries, 3));
|
||||
}
|
||||
|
||||
log.sort([](const NukiOpener::LogEntry& a, const NukiOpener::LogEntry& b) { return a.index < b.index; });
|
||||
|
||||
if(log.size() > 0)
|
||||
{
|
||||
_network->publishAuthorizationInfo(log, true);
|
||||
@@ -537,6 +539,8 @@ void NukiOpenerWrapper::updateAuthData(bool retrieved)
|
||||
log.resize(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG));
|
||||
}
|
||||
|
||||
log.sort([](const NukiOpener::LogEntry& a, const NukiOpener::LogEntry& b) { return a.index < b.index; });
|
||||
|
||||
Log->print(F("Log size: "));
|
||||
Log->println(log.size());
|
||||
|
||||
@@ -2073,11 +2077,11 @@ void NukiOpenerWrapper::setupHASS()
|
||||
|
||||
if(_preferences->getBool(preference_opener_continuous_mode))
|
||||
{
|
||||
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
|
||||
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, _publishAuthData, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
|
||||
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, _publishAuthData, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
|
||||
}
|
||||
|
||||
_hassSetupCompleted = true;
|
||||
|
||||
@@ -502,6 +502,8 @@ void NukiWrapper::updateAuthData(bool retrieved)
|
||||
log.resize(_preferences->getInt(preference_authlog_max_entries, 3));
|
||||
}
|
||||
|
||||
log.sort([](const NukiLock::LogEntry& a, const NukiLock::LogEntry& b) { return a.index < b.index; });
|
||||
|
||||
if(log.size() > 0)
|
||||
{
|
||||
_network->publishAuthorizationInfo(log, true);
|
||||
@@ -518,6 +520,8 @@ void NukiWrapper::updateAuthData(bool retrieved)
|
||||
log.resize(_preferences->getInt(preference_authlog_max_entries, MAX_AUTHLOG));
|
||||
}
|
||||
|
||||
log.sort([](const NukiLock::LogEntry& a, const NukiLock::LogEntry& b) { return a.index < b.index; });
|
||||
|
||||
Log->print(F("Log size: "));
|
||||
Log->println(log.size());
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#define preference_access_level (char*)"accLvl"
|
||||
#define preference_keypad_info_enabled (char*)"kpInfoEnabled"
|
||||
#define preference_keypad_control_enabled (char*)"kpCntrlEnabled"
|
||||
#define preference_keypad_publish_code (char*)"kpPubCode"
|
||||
#define preference_timecontrol_control_enabled (char*)"tcCntrlEnabled"
|
||||
#define preference_timecontrol_info_enabled (char*)"tcInfoEnabled"
|
||||
#define preference_publish_authdata (char*)"pubAuth"
|
||||
@@ -97,7 +98,7 @@ private:
|
||||
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_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled,
|
||||
preference_keypad_info_enabled, preference_acl, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled,
|
||||
preference_keypad_info_enabled, preference_keypad_publish_code, preference_acl, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled,
|
||||
preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl, preference_conf_opener_advanced_acl,
|
||||
preference_access_level, preference_register_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user,
|
||||
preference_cred_password, preference_publish_authdata, preference_publish_debug_info, preference_presence_detection_timeout, preference_disable_non_json,
|
||||
@@ -115,8 +116,8 @@ private:
|
||||
{
|
||||
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
|
||||
preference_enable_bootloop_reset, preference_webserver_enabled, preference_find_best_rssi, preference_restart_on_disconnect, preference_keypad_control_enabled,
|
||||
preference_keypad_info_enabled, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_ip_dhcp_enabled,
|
||||
preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled, preference_disable_non_json
|
||||
preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app,
|
||||
preference_ip_dhcp_enabled, preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled, preference_disable_non_json
|
||||
};
|
||||
|
||||
const bool isRedacted(const char* key) const
|
||||
|
||||
@@ -561,6 +561,11 @@ bool WebCfgServer::processArgs(String& message)
|
||||
_preferences->putBool(preference_keypad_info_enabled, (value == "1"));
|
||||
configChanged = true;
|
||||
}
|
||||
else if(key == "KPCODE")
|
||||
{
|
||||
_preferences->putBool(preference_keypad_publish_code, (value == "1"));
|
||||
configChanged = true;
|
||||
}
|
||||
else if(key == "KPENA")
|
||||
{
|
||||
_preferences->putBool(preference_keypad_control_enabled, (value == "1"));
|
||||
@@ -1400,12 +1405,13 @@ void WebCfgServer::buildAccLvlHtml(String &response)
|
||||
|
||||
if((_nuki != nullptr && _nuki->hasKeypad()) || (_nukiOpener != nullptr && _nukiOpener->hasKeypad()))
|
||||
{
|
||||
printCheckBox(response, "KPPUB", "Publish keypad codes information", _preferences->getBool(preference_keypad_info_enabled), "");
|
||||
printCheckBox(response, "KPPUB", "Publish keypad entries information", _preferences->getBool(preference_keypad_info_enabled), "");
|
||||
printCheckBox(response, "KPCODE", "Also publish keypad codes (<span style=\"color: #ff0000\">Disadvised for security reasons</span>)", _preferences->getBool(preference_keypad_publish_code, false), "");
|
||||
printCheckBox(response, "KPENA", "Add, modify and delete keypad codes", _preferences->getBool(preference_keypad_control_enabled), "");
|
||||
}
|
||||
printCheckBox(response, "TCPUB", "Publish time control entries information", _preferences->getBool(preference_timecontrol_info_enabled), "");
|
||||
printCheckBox(response, "TCENA", "Add, modify and delete time control entries", _preferences->getBool(preference_timecontrol_control_enabled), "");
|
||||
printCheckBox(response, "PUBAUTH", "Publish authorisation log (may reduce battery life)", _preferences->getBool(preference_publish_authdata), "");
|
||||
printCheckBox(response, "PUBAUTH", "Publish authorization log (may reduce battery life)", _preferences->getBool(preference_publish_authdata), "");
|
||||
response.concat("</table><br>");
|
||||
if(_nuki != nullptr)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user