Skip to content

Commit

Permalink
Merge pull request technyon#328 from iranl/ha-fixes
Browse files Browse the repository at this point in the history
Multiple fixes (Nuki ID + README + ACL + DoorSensor/Keypad)
  • Loading branch information
technyon committed Mar 26, 2024
2 parents e14877b + 1dcef13 commit ea34708
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 29 deletions.
53 changes: 43 additions & 10 deletions NukiOpenerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ void NukiOpenerWrapper::unpair()
{
_nukiOpener.unPairNuki();
_deviceId->assignNewId();
_preferences->remove(preference_nuki_id_opener);
_paired = false;
}

Expand Down Expand Up @@ -355,8 +356,8 @@ void NukiOpenerWrapper::updateKeyTurnerState()
{
Log->println(F("Nuki opener: Ring detected (Open)"));
_network->publishRing(false);
}
}

_network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
updateGpioOutputs();

Expand Down Expand Up @@ -395,17 +396,48 @@ void NukiOpenerWrapper::updateConfig()
readConfig();
readAdvancedConfig();
_configRead = true;
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2;
bool expectedConfig = true;

if(_nukiConfigValid)
{
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
_network->publishConfig(_nukiConfig);
if(_preferences->getUInt(preference_nuki_id_opener, 0) == 0 || _retryConfigCount == 10)
{
_preferences->putUInt(preference_nuki_id_opener, _nukiConfig.nukiId);
}

if(_preferences->getUInt(preference_nuki_id_opener, 0) == _nukiConfig.nukiId)
{
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2;
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
_network->publishConfig(_nukiConfig);
_retryConfigCount = 0;
}
else
{
expectedConfig = false;
++_retryConfigCount;
}
}
if(_nukiAdvancedConfigValid)
else
{
expectedConfig = false;
++_retryConfigCount;
}
if(_nukiAdvancedConfigValid && _preferences->getUInt(preference_nuki_id_opener, 0) == _nukiConfig.nukiId)
{
_network->publishAdvancedConfig(_nukiAdvancedConfig);
_retryConfigCount = 0;
}
else
{
expectedConfig = false;
++_retryConfigCount;
}
if(!expectedConfig && _retryConfigCount < 11)
{
unsigned long ts = millis();
_nextConfigUpdateTs = ts + 60000;
}
}

Expand Down Expand Up @@ -442,7 +474,7 @@ void NukiOpenerWrapper::updateAuthData()
void NukiOpenerWrapper::updateKeypad()
{
if(_preferences->getBool(preference_keypad_info_enabled)) return;

Log->print(F("Querying opener keypad: "));
Nuki::CmdResult result = _nukiOpener.retrieveKeypadEntries(0, 0xffff);
printCommandResult(result);
Expand Down Expand Up @@ -498,12 +530,12 @@ LockActionResult NukiOpenerWrapper::onLockActionReceivedCallback(const char *val
{
return LockActionResult::UnknownAction;
}

nukiOpenerPreferences = new Preferences();
nukiOpenerPreferences->begin("nukihub", true);
uint32_t aclPrefs[17];
nukiOpenerPreferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));

if((action == NukiOpener::LockAction::ActivateRTO && (int)aclPrefs[9] == 1) || (action == NukiOpener::LockAction::DeactivateRTO && (int)aclPrefs[10] == 1) || (action == NukiOpener::LockAction::ElectricStrikeActuation && (int)aclPrefs[11] == 1) || (action == NukiOpener::LockAction::ActivateCM && (int)aclPrefs[12] == 1) || (action == NukiOpener::LockAction::DeactivateCM && (int)aclPrefs[13] == 1) || (action == NukiOpener::LockAction::FobAction1 && (int)aclPrefs[14] == 1) || (action == NukiOpener::LockAction::FobAction2 && (int)aclPrefs[15] == 1) || (action == NukiOpener::LockAction::FobAction3 && (int)aclPrefs[16] == 1))
{
nukiOpenerPreferences->end();
Expand Down Expand Up @@ -752,6 +784,7 @@ void NukiOpenerWrapper::readAdvancedConfig()
void NukiOpenerWrapper::setupHASS()
{
if(!_nukiConfigValid) return;
if(_preferences->getUInt(preference_nuki_id_opener, 0) != _nukiConfig.nukiId) return;

String baseTopic = _preferences->getString(preference_mqtt_opener_path);
char uidString[20];
Expand Down
1 change: 1 addition & 0 deletions NukiOpenerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class NukiOpenerWrapper : public NukiOpener::SmartlockEventHandler
int _nrOfRetries = 0;
int _retryDelay = 0;
int _retryCount = 0;
int _retryConfigCount = 0;
int _retryLockstateCount = 0;
unsigned long _nextRetryTs = 0;
std::vector<uint16_t> _keypadCodeIds;
Expand Down
51 changes: 39 additions & 12 deletions NukiWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ void NukiWrapper::unpair()
{
_nukiLock.unPairNuki();
_deviceId->assignNewId();
_preferences->remove(preference_nuki_id_lock);
_paired = false;
}

Expand Down Expand Up @@ -361,16 +362,48 @@ void NukiWrapper::updateConfig()
readConfig();
readAdvancedConfig();
_configRead = true;
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2;
bool expectedConfig = true;

if(_nukiConfigValid)
{
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
_network->publishConfig(_nukiConfig);
if(_preferences->getUInt(preference_nuki_id_lock, 0) == 0 || _retryConfigCount == 10)
{
_preferences->putUInt(preference_nuki_id_lock, _nukiConfig.nukiId);
}

if(_preferences->getUInt(preference_nuki_id_lock, 0) == _nukiConfig.nukiId)
{
_hasKeypad = _nukiConfig.hasKeypad > 0 || _nukiConfig.hasKeypadV2;
_firmwareVersion = std::to_string(_nukiConfig.firmwareVersion[0]) + "." + std::to_string(_nukiConfig.firmwareVersion[1]) + "." + std::to_string(_nukiConfig.firmwareVersion[2]);
_hardwareVersion = std::to_string(_nukiConfig.hardwareRevision[0]) + "." + std::to_string(_nukiConfig.hardwareRevision[1]);
_network->publishConfig(_nukiConfig);
_retryConfigCount = 0;
}
else
{
expectedConfig = false;
++_retryConfigCount;
}
}
else
{
expectedConfig = false;
++_retryConfigCount;
}
if(_nukiAdvancedConfigValid)
if(_nukiAdvancedConfigValid && _preferences->getUInt(preference_nuki_id_lock, 0) == _nukiConfig.nukiId)
{
_network->publishAdvancedConfig(_nukiAdvancedConfig);
_retryConfigCount = 0;
}
else
{
expectedConfig = false;
++_retryConfigCount;
}
if(!expectedConfig && _retryConfigCount < 11)
{
unsigned long ts = millis();
_nextConfigUpdateTs = ts + 60000;
}
}

Expand Down Expand Up @@ -560,13 +593,6 @@ void NukiWrapper::onConfigUpdateReceived(const char *topic, const char *value)
_nukiLock.enableAutoLock(newValue);
_nextConfigUpdateTs = millis() + 300;
}
else if(strcmp(topic, mqtt_topic_config_auto_lock) == 0)
{
bool newValue = atoi(value) > 0;
if(!_nukiAdvancedConfigValid || _nukiAdvancedConfig.autoLockEnabled == newValue) return;
_nukiLock.enableAutoLock(newValue);
_nextConfigUpdateTs = millis() + 300;
}
}

void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
Expand Down Expand Up @@ -732,6 +758,7 @@ void NukiWrapper::readAdvancedConfig()
void NukiWrapper::setupHASS()
{
if(!_nukiConfigValid) return;
if(_preferences->getUInt(preference_nuki_id_lock, 0) != _nukiConfig.nukiId) return;

String baseTopic = _preferences->getString(preference_mqtt_lock_path);
char uidString[20];
Expand Down
1 change: 1 addition & 0 deletions NukiWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class NukiWrapper : public Nuki::SmartlockEventHandler
int _nrOfRetries = 0;
int _retryDelay = 0;
int _retryCount = 0;
int _retryConfigCount = 0;
int _retryLockstateCount = 0;
long _rssiPublishInterval = 0;
unsigned long _nextRetryTs = 0;
Expand Down
12 changes: 7 additions & 5 deletions PreferencesKeys.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define preference_config_version "confVersion"
#define preference_device_id_lock "deviceId"
#define preference_device_id_opener "deviceIdOp"
#define preference_nuki_id_lock "nukiId"
#define preference_nuki_id_opener "nukidOp"
#define preference_mqtt_broker "mqttbroker"
#define preference_mqtt_broker_port "mqttport"
#define preference_mqtt_user "mqttuser"
Expand Down Expand Up @@ -68,11 +70,10 @@ class DebugPreferences
private:
std::vector<char*> _keys =
{
preference_started_before, preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_mqtt_broker,
preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled,
preference_mqtt_lock_path, preference_opener_enabled, preference_opener_continuous_mode, preference_mqtt_opener_path,
preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_mqtt_ca,
preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url,
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_lock_enabled, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_continuous_mode, preference_mqtt_opener_path,
preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count,
preference_mqtt_ca, preference_mqtt_crt, preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url,
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_network_timeout, preference_restart_on_disconnect,
Expand All @@ -89,6 +90,7 @@ class DebugPreferences
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 =
{
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Feel free to join us on Discord: https://discord.gg/feB9FnMY
## Supported devices

<b>Supported ESP32 devices:</b>
- Any dual-core ESP32, except the ESP32-S3 (because of compilation issues)
- All dual-core ESP32 models with WIFI and BLE which are supported by Arduino Core 2.0.14 should work, but builds are currently only provided for the ESP32 and not for the ESP32-S3 or ESP32-C3.
- The ESP32-S2 has no BLE and as such can't run Nuki Hub.
- The ESP32-C6 and ESP32-H2 are not supported by Arduino Core 2.0.14 as such can't run Nuki Hub (at this time).

<b>Supported Nuki devices:</b>
- Nuki Smart Lock 1.0
Expand Down
40 changes: 39 additions & 1 deletion WebCfgServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ bool WebCfgServer::processArgs(String& message)
_preferences->putString(preference_cred_password, "");
configChanged = true;
}

if(aclLvlChanged)
{
_preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
Expand Down Expand Up @@ -1089,6 +1089,9 @@ void WebCfgServer::buildInfoHtml(String &response)
response.concat("MQTT connected: ");
response.concat(_network->mqttConnectionState() > 0 ? "Yes\n" : "No\n");

uint32_t aclPrefs[17];
_preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));

if(_nuki != nullptr)
{
response.concat("Lock firmware version: ");
Expand All @@ -1103,7 +1106,26 @@ void WebCfgServer::buildInfoHtml(String &response)
response.concat(_nuki->hasDoorSensor() ? "Yes\n" : "No\n");
response.concat("Lock has keypad: ");
response.concat(_nuki->hasKeypad() ? "Yes\n" : "No\n");
response.concat("Lock ACL (Lock): ");
response.concat((int)aclPrefs[0] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Unlock): ");
response.concat((int)aclPrefs[1] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Unlatch): ");
response.concat((int)aclPrefs[2] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Lock N Go): ");
response.concat((int)aclPrefs[3] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Lock N Go Unlatch): ");
response.concat((int)aclPrefs[4] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Full Lock): ");
response.concat((int)aclPrefs[5] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Fob Action 1): ");
response.concat((int)aclPrefs[6] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Fob Action 2): ");
response.concat((int)aclPrefs[7] ? "Allowed\n" : "Disallowed\n");
response.concat("Lock ACL (Fob Action 3): ");
response.concat((int)aclPrefs[8] ? "Allowed\n" : "Disallowed\n");
}

if(_nukiOpener != nullptr)
{
response.concat("Opener firmware version: ");
Expand All @@ -1115,6 +1137,22 @@ void WebCfgServer::buildInfoHtml(String &response)
response.concat(_nukiOpener->isPaired() ? _nukiOpener->isPinSet() ? "Yes\n" : "No\n" : "-\n");
response.concat("Opener has keypad: ");
response.concat(_nukiOpener->hasKeypad() ? "Yes\n" : "No\n");
response.concat("Opener ACL (Activate Ring-to-Open): ");
response.concat((int)aclPrefs[9] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Deactivate Ring-to-Open): ");
response.concat((int)aclPrefs[10] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Electric Strike Actuation): ");
response.concat((int)aclPrefs[11] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Activate Continuous Mode): ");
response.concat((int)aclPrefs[12] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Deactivate Continuous Mode): ");
response.concat((int)aclPrefs[13] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Fob Action 1): ");
response.concat((int)aclPrefs[14] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Fob Action 2): ");
response.concat((int)aclPrefs[15] ? "Allowed\n" : "Disallowed\n");
response.concat("Opener ACL (Fob Action 3): ");
response.concat((int)aclPrefs[16] ? "Allowed\n" : "Disallowed\n");
}

response.concat("Network device: ");
Expand Down
4 changes: 4 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ bool initPreferences()
{
preferences->putBool(preference_started_before, true);
preferences->putBool(preference_lock_enabled, true);
preferences->putBool(preference_admin_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));
}
else
{
Expand Down

0 comments on commit ea34708

Please sign in to comment.