397 lines
12 KiB
C++
397 lines
12 KiB
C++
#include <cstring>
|
|
#include "NukiOfficial.h"
|
|
#include "Logger.h"
|
|
#include "PreferencesKeys.h"
|
|
#include "../lib/nuki_ble/src/NukiLockUtils.h"
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
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<char *> NukiOfficial::getOffTopics() const
|
|
{
|
|
return offTopics;
|
|
}
|