#include #include "NukiOfficial.h" #include "Logger.h" #include "PreferencesKeys.h" #include "../lib/nuki_ble/src/NukiLockUtils.h" #include #include NukiOfficial::NukiOfficial(Preferences *preferences) { offEnabled = preferences->getBool(preference_official_hybrid_enabled, false); _disableNonJSON = preferences->getBool(preference_disable_non_json, false); } void NukiOfficial::setUid(const uint32_t& uid) { char uidString[20]; itoa(uid, uidString, 16); for(char* c=uidString; *c=toupper(*c); ++c); strcpy(mqttPath, "nuki/"); strcat(mqttPath, uidString); offTopics.reserve(10); //_offTopics.push_back(mqtt_topic_official_mode); offTopics.push_back((char*)mqtt_topic_official_state); offTopics.push_back((char*)mqtt_topic_official_batteryCritical); offTopics.push_back((char*)mqtt_topic_official_batteryChargeState); offTopics.push_back((char*)mqtt_topic_official_batteryCharging); offTopics.push_back((char*)mqtt_topic_official_keypadBatteryCritical); offTopics.push_back((char*)mqtt_topic_official_doorsensorState); offTopics.push_back((char*)mqtt_topic_official_doorsensorBatteryCritical); offTopics.push_back((char*)mqtt_topic_official_connected); offTopics.push_back((char*)mqtt_topic_official_commandResponse); offTopics.push_back((char*)mqtt_topic_official_lockActionEvent); } void NukiOfficial::setPublisher(NukiPublisher *publisher) { _publisher = publisher; } const char *NukiOfficial::getMqttPath() const { return mqttPath; } void NukiOfficial::buildMqttPath(const char *path, char *outPath) { int offset = 0; char inPath[181] = {0}; memcpy(inPath, mqttPath, sizeof(mqttPath)); for(const char& c : inPath) { if(c == 0x00) { break; } outPath[offset] = c; ++offset; } int i=0; while(outPath[i] != 0x00) { outPath[offset] = path[i]; ++i; ++offset; } outPath[i+1] = 0x00; } bool NukiOfficial::comparePrefixedPath(const char *fullPath, const char *subPath) { char prefixedPath[500]; buildMqttPath(subPath, prefixedPath); return strcmp(fullPath, prefixedPath) == 0; } void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value) { char str[50]; bool publishBatteryJson = false; memset(&str, 0, sizeof(str)); Log->println("Official Nuki change received"); Log->print(("Topic: ")); Log->println(topic); Log->print(("Value: ")); Log->println(value); if(strcmp(topic, mqtt_topic_official_connected) == 0) { Log->print(("Connected: ")); Log->println((strcmp(value, "true") == 0 ? 1 : 0)); offConnected = (strcmp(value, "true") == 0 ? 1 : 0); _publisher->publishBool(mqtt_topic_hybrid_state, offConnected, true); } else if(strcmp(topic, mqtt_topic_official_state) == 0) { offState = atoi(value); _statusUpdated = true; Log->println(("Lock: Updating status on Hybrid state change")); _publisher->publishBool(mqtt_topic_hybrid_state, offConnected, true); NukiLock::lockstateToString((NukiLock::LockState)offState, str); _publisher->publishString(mqtt_topic_lock_state, str, true); Log->print(("Lockstate: ")); Log->println(str); _offStateToPublish = (NukiLock::LockState)offState; _hasOffStateToPublish = true; } else if(strcmp(topic, mqtt_topic_official_doorsensorState) == 0) { offDoorsensorState = atoi(value); _statusUpdated = true; Log->println(("Lock: Updating status on Hybrid door sensor state change")); _publisher->publishBool(mqtt_topic_lock_status_updated, _statusUpdated, true); NukiLock::doorSensorStateToString((NukiLock::DoorSensorState)offDoorsensorState, str); Log->print(("Doorsensor state: ")); Log->println(str); _publisher->publishString(mqtt_topic_lock_door_sensor_state, str, true); } else if(strcmp(topic, mqtt_topic_official_batteryCritical) == 0) { offCritical = (strcmp(value, "true") == 0 ? 1 : 0); Log->print(("Battery critical: ")); Log->println(offCritical); if(!_disableNonJSON) { _publisher->publishBool(mqtt_topic_battery_critical, offCritical, true); } publishBatteryJson = true; } else if(strcmp(topic, mqtt_topic_official_batteryCharging) == 0) { offCharging = (strcmp(value, "true") == 0 ? 1 : 0); Log->print(("Battery charging: ")); Log->println(offCharging); if(!_disableNonJSON) { _publisher->publishBool(mqtt_topic_battery_charging, offCharging, true); } publishBatteryJson = true; } else if(strcmp(topic, mqtt_topic_official_batteryChargeState) == 0) { offChargeState = atoi(value); Log->print(("Battery level: ")); Log->println(offChargeState); if(!_disableNonJSON) { _publisher->publishInt(mqtt_topic_battery_level, offChargeState, true); } publishBatteryJson = true; } else if(strcmp(topic, mqtt_topic_official_keypadBatteryCritical) == 0) { offKeypadCritical = (strcmp(value, "true") == 0 ? 1 : 0); if(!_disableNonJSON) { _publisher->publishBool(mqtt_topic_battery_keypad_critical, offKeypadCritical, true); } publishBatteryJson = true; } else if(strcmp(topic, mqtt_topic_official_doorsensorBatteryCritical) == 0) { offDoorsensorCritical = (strcmp(value, "true") == 0 ? 1 : 0); if(!_disableNonJSON) { _publisher->publishBool(mqtt_topic_battery_doorsensor_critical, offDoorsensorCritical, true); } publishBatteryJson = true; } else if(strcmp(topic, mqtt_topic_official_commandResponse) == 0) { offCommandResponse = atoi(value); if(offCommandResponse == 0) { clearOffCommandExecutedTs(); } char resultStr[15] = {0}; NukiLock::cmdResultToString((Nuki::CmdResult)offCommandResponse, resultStr); _publisher->publishString(mqtt_topic_lock_action_command_result, resultStr, true); } else if(strcmp(topic, mqtt_topic_official_lockActionEvent) == 0) { clearAuthId(); clearOffCommandExecutedTs(); offLockActionEvent = (char*)value; String LockActionEvent = offLockActionEvent; const int ind1 = LockActionEvent.indexOf(','); const int ind2 = LockActionEvent.indexOf(',', ind1+1); const int ind3 = LockActionEvent.indexOf(',', ind2+1); const int ind4 = LockActionEvent.indexOf(',', ind3+1); const int ind5 = LockActionEvent.indexOf(',', ind4+1); offLockAction = atoi(LockActionEvent.substring(0, ind1).c_str()); offTrigger = atoi(LockActionEvent.substring(ind1 + 1, ind2 + 1).c_str()); offAuthId = atoi(LockActionEvent.substring(ind2 + 1, ind3 + 1).c_str()); offCodeId = atoi(LockActionEvent.substring(ind3 + 1, ind4 + 1).c_str()); offContext = atoi(LockActionEvent.substring(ind4 + 1, ind5 + 1).c_str()); memset(&str, 0, sizeof(str)); lockactionToString((NukiLock::LockAction)offLockAction, str); _publisher->publishString(mqtt_topic_lock_last_lock_action, str, true); memset(&str, 0, sizeof(str)); triggerToString((NukiLock::Trigger)offTrigger, str); _publisher->publishString(mqtt_topic_lock_trigger, str, true); if(offAuthId > 0 || offCodeId > 0) { if(offCodeId > 0) { _authId = offCodeId; switch(offContext) { case 0: _publisher->publishString(mqtt_topic_lock_lock_action_context, "keypadBackKey", true); break; case 1: _publisher->publishString(mqtt_topic_lock_lock_action_context, "keypadCode", true); break; case 2: _publisher->publishString(mqtt_topic_lock_lock_action_context, "keypadFingerprint", true); break; default: _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); break; } } else { _authId = offAuthId; switch(offTrigger) { case 0: if (offContext == 1) { _publisher->publishString(mqtt_topic_lock_lock_action_context, "autoUnlock", true); } else { _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); } break; case 2: if (offContext > 0) { _publisher->publishString(mqtt_topic_lock_lock_action_context, String("button") + String(offContext) + "press", true); } else { _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); } break; case 3: if (offContext > 0) { _publisher->publishString(mqtt_topic_lock_lock_action_context, String("fob") + String(offContext) + "press", true); } else { _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); } break; default: _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); break; } } _hasAuthId = true; } else { _publisher->publishString(mqtt_topic_lock_lock_action_context, "", true); } } if(publishBatteryJson) { JsonDocument jsonBattery; char _resbuf[2048]; jsonBattery["critical"] = offCritical ? "1" : "0"; jsonBattery["charging"] = offCharging ? "1" : "0"; jsonBattery["level"] = offChargeState; jsonBattery["keypadCritical"] = offKeypadCritical ? "1" : "0"; jsonBattery["doorSensorCritical"] = offDoorsensorCritical ? "1" : "0"; serializeJson(jsonBattery, _resbuf, sizeof(_resbuf)); _publisher->publishString(mqtt_topic_battery_basic_json, _resbuf, true); } } const bool NukiOfficial::getStatusUpdated() { bool stu = _statusUpdated; _statusUpdated = false; return stu; } const bool NukiOfficial::hasOffStateToPublish() { bool hasOff = _hasOffStateToPublish; _hasOffStateToPublish = false; return hasOff; } const NukiLock::LockState NukiOfficial::getOffStateToPublish() const { return _offStateToPublish; } const uint32_t NukiOfficial::getAuthId() const { return _authId; } const bool NukiOfficial::hasAuthId() const { return _hasAuthId; } void NukiOfficial::clearAuthId() { _hasAuthId = false; _authId = 0; } const bool NukiOfficial::getOffConnected() const { return offConnected; } const bool NukiOfficial::getOffEnabled() const { return offEnabled; } const uint8_t NukiOfficial::getOffDoorsensorState() const { return offDoorsensorState; } const uint8_t NukiOfficial::getOffState() const { return offState; } const uint8_t NukiOfficial::getOffLockAction() const { return offLockAction; } const uint8_t NukiOfficial::getOffTrigger() const { return offTrigger; } const uint8_t NukiOfficial::getOffContext() const { return offContext; } const int64_t NukiOfficial::getOffCommandExecutedTs() const { return offCommandExecutedTs; } void NukiOfficial::setOffCommandExecutedTs(const int64_t &value) { offCommandExecutedTs = value; } void NukiOfficial::clearOffCommandExecutedTs() { offCommandExecutedTs = 0; } const std::vector NukiOfficial::getOffTopics() const { return offTopics; }