diff --git a/app/FingerLogic.cpp b/app/FingerLogic.cpp index c0ac909..1e94ee1 100644 --- a/app/FingerLogic.cpp +++ b/app/FingerLogic.cpp @@ -16,7 +16,9 @@ CFingerLogic::CFingerLogic(CMain *pMain) memset(&m_FingerParams, 0, sizeof(m_FingerParams)); memset(m_aFingerSlots, 0, sizeof(m_aFingerSlots)); m_FingerSlotsAdded = 0; + m_ErrorCounter = 0; + m_InitTimer.initializeMs(100, TimerDelegate(&CFingerLogic::InitFinger, this)); m_PowerOffTimer.initializeMs(1000, TimerDelegate(&CFingerLogic::PowerOff, this)); } @@ -31,8 +33,13 @@ void CFingerLogic::SetState(FingerLogicState state) { m_State = state; + if(m_State == STATE_ERROR) + m_ErrorCounter++; + if(m_State == STATE_READY || m_State == STATE_ERROR) - m_PowerOffTimer.start(false); + { + m_PowerOffTimer.startOnce(); + } else { m_PowerOffTimer.stop(); @@ -47,9 +54,8 @@ void CFingerLogic::PowerOff() debugf("PowerOff()"); m_Power = false; - Main().FingerEnable(false); - wifi_set_sleep_type(LIGHT_SLEEP_T); - system_soft_wdt_feed(); + m_ErrorCounter = 0; + Main().FingerPower(false); } void CFingerLogic::PowerOn() @@ -59,14 +65,15 @@ void CFingerLogic::PowerOn() debugf("PowerOn()"); m_Power = true; - Main().FingerEnable(true); - wifi_set_sleep_type(MODEM_SLEEP_T); + Main().FingerPower(true); + system_soft_wdt_feed(); delayMilliseconds(100); + system_soft_wdt_feed(); } -void CFingerLogic::OnFingerInterrupt(bool finger) +void CFingerLogic::OnFinger(bool finger) { - debugf("OnFingerInterrupt: %s", finger ? "DOWN" : "UP"); + debugf("OnFinger: %s", finger ? "DOWN" : "UP"); m_Finger = finger; if(finger) @@ -122,15 +129,20 @@ void CFingerLogic::InitFinger() if(m_State > STATE_INIT_VERIFYPASSWORD) return; + if(m_ErrorCounter > 100) + return; + SetState(STATE_INIT_VERIFYPASSWORD); FingerPrint().AsyncVerifyPassword((VerifyPasswordCallback)InitFinger_OnVerifyPassword, this); - m_Timer.initializeMs(100, TimerDelegate(&CFingerLogic::InitFinger, this)).start(); + m_InitTimer.start(); + m_ErrorCounter++; } void CFingerLogic::InitFinger_OnVerifyPassword(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) { - pThis->m_Timer.stop(); + pThis->m_ErrorCounter--; + pThis->m_InitTimer.stop(); debugf("InitFinger_OnVerifyPassword: (%d) %s", error, errorStr); if(error == ERROR_OK) @@ -157,11 +169,38 @@ void CFingerLogic::InitFinger_OnReadSystemParameters(CFingerLogic *pThis, Finger debugf("packetLength: %d", param->packetLength); debugf("baudRate: %d", param->baudRate); + if(param->securityLevel != pThis->Main().Settings().m_SecurityLevel) + { + pThis->SetState(STATE_INIT_SETSYSTEM_SECURITYLEVEL); + pThis->FingerPrint().AsyncSetSystemParameter((SetSystemParameterCallback)InitFinger_OnSetSystemSecurityLevel, pThis, FINGERPRINT_SECURITY_REG_ADDR, pThis->Main().Settings().m_SecurityLevel); + } + else + { + pThis->SetState(STATE_INIT_READTEMPLATEMAP); + pThis->FingerPrint().AsyncReadTemplateMap((ReadTemplateMapCallback)InitFinger_OnReadTemplateMap, pThis, 0); + } + } + else + { + pThis->SetState(STATE_ERROR); + pThis->m_InitTimer.start(); + } +} + +void CFingerLogic::InitFinger_OnSetSystemSecurityLevel(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) +{ + debugf("InitFinger_OnSetSystemSecurityLevel: (%d) %s", error, errorStr); + + if(error == ERROR_OK) + { pThis->SetState(STATE_INIT_READTEMPLATEMAP); pThis->FingerPrint().AsyncReadTemplateMap((ReadTemplateMapCallback)InitFinger_OnReadTemplateMap, pThis, 0); } else + { pThis->SetState(STATE_ERROR); + pThis->m_InitTimer.start(); + } } void CFingerLogic::InitFinger_OnReadTemplateMap(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, uint8_t *pData, uint16_t dataLen) @@ -241,7 +280,10 @@ void CFingerLogic::InitFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintErr pThis->FingerPrint().AsyncDownloadCharacteristics((DownloadCharacteristicsCallback)InitFinger_OnDownloadCharacteristics, pThis, 0x01); } else + { pThis->SetState(STATE_ERROR); + pThis->m_InitTimer.start(); + } } void CFingerLogic::InitFinger_OnDownloadCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int8_t *pChar, uint16_t charLen) @@ -282,7 +324,10 @@ void CFingerLogic::InitFinger_OnDownloadCharacteristics(CFingerLogic *pThis, Fin pThis->FingerPrint().AsyncLoadTemplate((LoadTemplateCallback)InitFinger_OnLoadTemplate, pThis, position, 0x01); } else + { pThis->SetState(STATE_ERROR); + pThis->m_InitTimer.start(); + } } @@ -537,9 +582,7 @@ void CFingerLogic::EnrollFinger_OnCreateTemplate(CFingerLogic *pThis, FingerPrin pThis->FingerPrint().AsyncStoreTemplate((StoreTemplateCallback)EnrollFinger_OnStoreTemplate, pThis, pThis->m_iBuffer, 0x01); } else - { pThis->SetState(STATE_READY); - } } void CFingerLogic::EnrollFinger_OnStoreTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, uint16_t positionNumber) @@ -554,9 +597,7 @@ void CFingerLogic::EnrollFinger_OnStoreTemplate(CFingerLogic *pThis, FingerPrint pThis->FingerPrint().AsyncLoadTemplate((LoadTemplateCallback)EnrollFinger_OnLoadTemplate, pThis, positionNumber, 0x01); } else - { pThis->SetState(STATE_READY); - } } void CFingerLogic::EnrollFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) @@ -570,9 +611,7 @@ void CFingerLogic::EnrollFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintE pThis->FingerPrint().AsyncDownloadCharacteristics((DownloadCharacteristicsCallback)EnrollFinger_OnDownloadCharacteristics, pThis, 0x01); } else - { pThis->SetState(STATE_READY); - } } void CFingerLogic::EnrollFinger_OnDownloadCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int8_t *pChar, uint16_t charLen) @@ -586,13 +625,20 @@ void CFingerLogic::EnrollFinger_OnDownloadCharacteristics(CFingerLogic *pThis, F ctx.update(pChar, charLen); uint8_t *digest = ctx.getHash().data(); - Serial1.printf("NEW Finger %d hexdigest: ", pThis->m_iBuffer); - for(uint8_t i = 0; i < sizeof(digest); i++) - Serial1.printf("%x", digest[i]); - Serial1.printf("\n"); - pThis->Main().OnFingerEnrolled(pThis->m_iBuffer, digest); } pThis->SetState(STATE_READY); } + +void CFingerLogic::SetSecurityLevel(int securityLevel) +{ + SetState(STATE_SETSYSTEM_SECURITYLEVEL); + FingerPrint().AsyncSetSystemParameter((SetSystemParameterCallback)SetSecurityLevel_OnSetSystemSecurityLevel, this, FINGERPRINT_SECURITY_REG_ADDR, securityLevel); +} + +void CFingerLogic::SetSecurityLevel_OnSetSystemSecurityLevel(CFingerLogic *pThis, FingerPrintError error, const char *errorStr) +{ + debugf("SetSecurityLevel_OnSetSystemSecurityLevel: (%d) %s", error, errorStr); + pThis->SetState(STATE_READY); +} diff --git a/app/FingerLogic.h b/app/FingerLogic.h index ddc5081..83a13d0 100644 --- a/app/FingerLogic.h +++ b/app/FingerLogic.h @@ -11,6 +11,7 @@ enum FingerLogicState STATE_INIT_VERIFYPASSWORD, STATE_INIT_READSYSTEMPARAMETERS, + STATE_INIT_SETSYSTEM_SECURITYLEVEL, STATE_INIT_READTEMPLATEMAP, STATE_INIT_VERIFYTEMPLATES, @@ -33,7 +34,9 @@ enum FingerLogicState STATE_ENROLL_CREATETEMPLATE, STATE_ENROLL_STORETEMPLATE, STATE_ENROLL_LOADTEMPLATE, - STATE_ENROLL_DOWNLOADCHARACTERISTICS + STATE_ENROLL_DOWNLOADCHARACTERISTICS, + + STATE_SETSYSTEM_SECURITYLEVEL }; class CFingerLogic @@ -41,7 +44,7 @@ class CFingerLogic public: CFingerLogic(class CMain *pMain); void Init(CFingerPrint *pFingerPrint); - void OnFingerInterrupt(bool finger); + void OnFinger(bool finger); bool FingerSlot(uint16_t index); bool FingerSlot(uint16_t index, bool value); @@ -50,6 +53,7 @@ public: void InitFinger(); static void InitFinger_OnVerifyPassword(CFingerLogic *pThis, FingerPrintError error, const char *errorStr); static void InitFinger_OnReadSystemParameters(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, CFingerSystemParameters *param); + static void InitFinger_OnSetSystemSecurityLevel(CFingerLogic *pThis, FingerPrintError error, const char *errorStr); static void InitFinger_OnGetTemplates(CFingerLogic *pThis, FingerPrintError error, const char *errorStr); static void InitFinger_OnReadTemplateMap(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, uint8_t *pData, uint16_t dataLen); void InitFinger_VerifyTemplates(); @@ -76,6 +80,9 @@ public: static void EnrollFinger_OnLoadTemplate(CFingerLogic *pThis, FingerPrintError error, const char *errorStr); static void EnrollFinger_OnDownloadCharacteristics(CFingerLogic *pThis, FingerPrintError error, const char *errorStr, int8_t *pChar, uint16_t charLen); + void SetSecurityLevel(int securityLevel); + static void SetSecurityLevel_OnSetSystemSecurityLevel(CFingerLogic *pThis, FingerPrintError error, const char *errorStr); + CMain &Main() { return *m_pMain; } CFingerPrint &FingerPrint() { return *m_pFingerPrint; } @@ -84,11 +91,13 @@ private: void PowerOff(); void PowerOn(); void SetState(FingerLogicState state); + Timer m_InitTimer; Timer m_PowerOffTimer; CMain *m_pMain; CFingerPrint *m_pFingerPrint; FingerLogicState m_State; + int m_ErrorCounter; bool m_Finger; CFingerSystemParameters m_FingerParams; @@ -97,7 +106,6 @@ private: int32_t m_iBuffer; - Timer m_Timer; void *m_fnUserCallback; void *m_pUserData; }; diff --git a/app/FingerPrint.h b/app/FingerPrint.h index 2bccf4b..feb9898 100644 --- a/app/FingerPrint.h +++ b/app/FingerPrint.h @@ -69,6 +69,36 @@ enum FingerPrintError ERROR_COMMUNICATIONPORT = 0x1D, // fail to operate the communication port }; +#define FINGERPRINT_BAUD_REG_ADDR 0x4 //!< BAUDRATE register address +#define FINGERPRINT_BAUDRATE_9600 0x1 //!< UART baud 9600 +#define FINGERPRINT_BAUDRATE_19200 0x2 //!< UART baud 19200 +#define FINGERPRINT_BAUDRATE_28800 0x3 //!< UART baud 28800 +#define FINGERPRINT_BAUDRATE_38400 0x4 //!< UART baud 38400 +#define FINGERPRINT_BAUDRATE_48000 0x5 //!< UART baud 48000 +#define FINGERPRINT_BAUDRATE_57600 0x6 //!< UART baud 57600 +#define FINGERPRINT_BAUDRATE_67200 0x7 //!< UART baud 67200 +#define FINGERPRINT_BAUDRATE_76800 0x8 //!< UART baud 76800 +#define FINGERPRINT_BAUDRATE_86400 0x9 //!< UART baud 86400 +#define FINGERPRINT_BAUDRATE_96000 0xA //!< UART baud 96000 +#define FINGERPRINT_BAUDRATE_105600 0xB //!< UART baud 105600 +#define FINGERPRINT_BAUDRATE_115200 0xC //!< UART baud 115200 + +#define FINGERPRINT_SECURITY_REG_ADDR 0x5 //!< Security level register address +// The safety level is 1 The highest rate of false recognition , The rejection +// rate is the lowest . The safety level is 5 The lowest tate of false +// recognition, The rejection rate is the highest . +#define FINGERPRINT_SECURITY_LEVEL_1 0X1 //!< Security level 1 +#define FINGERPRINT_SECURITY_LEVEL_2 0X2 //!< Security level 2 +#define FINGERPRINT_SECURITY_LEVEL_3 0X3 //!< Security level 3 +#define FINGERPRINT_SECURITY_LEVEL_4 0X4 //!< Security level 4 +#define FINGERPRINT_SECURITY_LEVEL_5 0X5 //!< Security level 5 + +#define FINGERPRINT_PACKET_REG_ADDR 0x6 //!< Packet size register address +#define FINGERPRINT_PACKET_SIZE_32 0X0 //!< Packet size is 32 Byte +#define FINGERPRINT_PACKET_SIZE_64 0X1 //!< Packet size is 64 Byte +#define FINGERPRINT_PACKET_SIZE_128 0X2 //!< Packet size is 128 Byte +#define FINGERPRINT_PACKET_SIZE_256 0X3 //!< Packet size is 256 Byte + enum RecvStates { RECV_DONE = 0, @@ -92,6 +122,7 @@ typedef void (CFingerPrint::*RecvCallback)(FingerPrintIdent ident, uint8_t *pDat typedef void (*VerifyPasswordCallback)(void *pUser, FingerPrintError error, const char *errorStr); typedef void (*ReadSystemParametersCallback)(void *pUser, FingerPrintError error, const char *errorStr, CFingerSystemParameters *param); +typedef void (*SetSystemParameterCallback)(void *pUser, FingerPrintError error, const char *errorStr); typedef void (*ReadImageCallback)(void *pUser, FingerPrintError error, const char *errorStr); typedef void (*ConvertImageCallback)(void *pUser, FingerPrintError error, const char *errorStr); typedef void (*SearchTemplateCallback)(void *pUser, FingerPrintError error, const char *errorStr, int16_t position, int16_t score); @@ -112,11 +143,13 @@ public: int VerifyPassword(); int ReadSystemParameters(uint8_t aResponse[17]); + int SetSystemParameter(uint8_t regAddr, uint8_t value); int DeleteTemplate(uint16_t positionStart, uint16_t count); int EmptyDatabase(); int AsyncVerifyPassword(VerifyPasswordCallback fnCallback, void *pUser); int AsyncReadSystemParameters(ReadSystemParametersCallback fnCallback, void *pUser); + int AsyncSetSystemParameter(SetSystemParameterCallback fnCallback, void *pUser, uint8_t regAddr, uint8_t value); int AsyncReadImage(ReadImageCallback fnCallback, void *pUser); int AsyncConvertImage(ConvertImageCallback fnCallback, void *pUser, uint8_t numCharBuffer); int AsyncSearchTemplate(SearchTemplateCallback fnCallback, void *pUser, uint8_t numCharBuffer, uint16_t positionStart, uint16_t numTemplates); @@ -130,6 +163,7 @@ public: private: void OnAsyncVerifyPassword(FingerPrintIdent ident, uint8_t *pData, uint16_t length); void OnAsyncReadSystemParameters(FingerPrintIdent ident, uint8_t *pData, uint16_t length); + void OnAsyncSetSystemParameter(FingerPrintIdent ident, uint8_t *pData, uint16_t length); void OnAsyncReadImage(FingerPrintIdent ident, uint8_t *pData, uint16_t length); void OnAsyncConvertImage(FingerPrintIdent ident, uint8_t *pData, uint16_t length); void OnAsyncSearchTemplate(FingerPrintIdent ident, uint8_t *pData, uint16_t length); diff --git a/app/FingerPrint_API.cpp b/app/FingerPrint_API.cpp index a2ab40b..473fce3 100644 --- a/app/FingerPrint_API.cpp +++ b/app/FingerPrint_API.cpp @@ -50,6 +50,31 @@ int CFingerPrint::ReadSystemParameters(uint8_t aResponse[17]) return error; } +int CFingerPrint::SetSystemParameter(uint8_t regAddr, uint8_t value) +{ + uint8_t aPayload[] = { + COMMAND_SETSYSPARA, + regAddr, + value + }; + + Write(IDENT_COMMAND, aPayload, sizeof(aPayload)); + + FingerPrintIdent ident; + uint8_t aResponse[1]; + int ret = Recv(&ident, aResponse, sizeof(aResponse)); + m_RecvState = RECV_DROP; + + if(ret < 0) + return ret; + + if(ident != IDENT_ACK) + return ERROR_COMMUNICATION; + + uint8_t error = aResponse[0]; + return error; +} + int CFingerPrint::DeleteTemplate(uint16_t positionStart, uint16_t count) { uint8_t aPayload[] = { diff --git a/app/FingerPrint_AsyncAPI.cpp b/app/FingerPrint_AsyncAPI.cpp index 8fcbe50..40e42b8 100644 --- a/app/FingerPrint_AsyncAPI.cpp +++ b/app/FingerPrint_AsyncAPI.cpp @@ -90,6 +90,40 @@ void CFingerPrint::OnAsyncReadSystemParameters(FingerPrintIdent ident, uint8_t * } +int CFingerPrint::AsyncSetSystemParameter(SetSystemParameterCallback fnCallback, void *pUser, uint8_t regAddr, uint8_t value) +{ + uint8_t aPayload[] = { + COMMAND_SETSYSPARA, + regAddr, + value + }; + + m_fnRecvCallback = &CFingerPrint::OnAsyncSetSystemParameter; + m_fnUserCallback = (void *)fnCallback; + m_pUserData = pUser; + + Write(IDENT_COMMAND, aPayload, sizeof(aPayload)); + + return 0; +} + +void CFingerPrint::OnAsyncSetSystemParameter(FingerPrintIdent ident, uint8_t *pData, uint16_t length) +{ + m_RecvState = RECV_DROP; + + if(ident != IDENT_ACK) + { + ((SetSystemParameterCallback)m_fnUserCallback)(m_pUserData, ERROR_COMMUNICATION, "The received packet is no ack packet!"); + return; + } + + uint8_t error = pData[0]; + const char *errorStr = ExplainFingerError(error); + + ((SetSystemParameterCallback)m_fnUserCallback)(m_pUserData, (FingerPrintError)error, errorStr); +} + + int CFingerPrint::AsyncReadImage(ReadImageCallback fnCallback, void *pUser) { uint8_t aPayload[] = { diff --git a/app/Settings.cpp b/app/Settings.cpp index 4a7fa0d..7044fdc 100644 --- a/app/Settings.cpp +++ b/app/Settings.cpp @@ -11,10 +11,11 @@ CSettings::CSettings() strcpy(m_aPSK, ""); m_DHCP = true; strcpy(m_aHostname, "safeweb"); - m_Address = IPAddress(0, 0, 0, 0); - m_Netmask = IPAddress(0, 0, 0, 0); - m_Gateway = IPAddress(0, 0, 0, 0); + m_Address = IpAddress(0, 0, 0, 0); + m_Netmask = IpAddress(0, 0, 0, 0); + m_Gateway = IpAddress(0, 0, 0, 0); memset(m_aLockCode, 0, sizeof(m_aLockCode)); + m_SecurityLevel = 4; } bool CSettings::Exists() @@ -53,6 +54,11 @@ bool CSettings::Load() m_Netmask = network["netmask"].as(); m_Gateway = network["gateway"].as(); + JsonObject mqtt = doc["mqtt"]; + strncpy(m_aMqttName, mqtt["client_name"], sizeof(m_aMqttName)); + m_MqttURL = Url("mqtt", mqtt["username"], mqtt["password"], mqtt["host"], mqtt["port"]); + m_MqttUnlock = bool(mqtt["unlock"]); + JsonArray lockCode = doc["lock_code"]; uint8_t tmp = min(lockCode.size(), sizeof(m_aLockCode)); for(uint8_t i = 0; i < tmp; i++) @@ -73,6 +79,8 @@ bool CSettings::Load() m_FingerPrints[finger.m_FingerNum] = finger; } + m_SecurityLevel = min(max(int(doc["security_level"]), 1), 5); + delete[] pData; return true; } @@ -93,6 +101,14 @@ void CSettings::Save() network["netmask"] = m_Netmask.toString(); network["gateway"] = m_Gateway.toString(); + JsonObject mqtt = doc.createNestedObject("mqtt"); + mqtt["client_name"] = m_aMqttName; + mqtt["host"] = m_MqttURL.Host; + mqtt["port"] = m_MqttURL.getPort(); + mqtt["username"] = m_MqttURL.User; + mqtt["password"] = m_MqttURL.Password; + mqtt["unlock"] = m_MqttUnlock; + JsonArray lockCode = doc.createNestedArray("lock_code"); for(uint8_t i = 0; i < sizeof(m_aLockCode); i++) lockCode.add(m_aLockCode[i]); @@ -112,6 +128,8 @@ void CSettings::Save() obj["digest"] = String(aHexDigest); } + doc["security_level"] = m_SecurityLevel; + String docString; serializeJsonPretty(doc, docString); fileSetContent(APP_SETTINGS_FILE, docString); diff --git a/app/Settings.h b/app/Settings.h index d5a71fb..c08060e 100644 --- a/app/Settings.h +++ b/app/Settings.h @@ -24,6 +24,10 @@ public: IpAddress m_Netmask; IpAddress m_Gateway; + Url m_MqttURL; + char m_aMqttName[64]; + bool m_MqttUnlock; + uint8_t m_aLockCode[8]; struct CFingerPrint @@ -33,6 +37,8 @@ public: uint8_t m_aDigest[SHA256_SIZE]; }; HashMap m_FingerPrints; + + int m_SecurityLevel; }; #endif diff --git a/app/application.cpp b/app/application.cpp index 7dc4bbb..856d3b6 100644 --- a/app/application.cpp +++ b/app/application.cpp @@ -1,27 +1,60 @@ #include #include "FingerPrint.h" +#include "utils.h" #include "main.h" HardwareSerial Serial1(UART_ID_1); NtpClient ntpClient("at.pool.ntp.org", 3600); -void IRAM_ATTR OnFingerInterrupt() +static SimpleTimer procTimer; +volatile uint8_t procTimerLoops = 0; +void OnProcTimer() { - // LOW = FINGER, HIGH = NO FINGER - bool status = digitalRead(FINGER_DETECT_PIN); + const bool finger = !digitalRead(FINGER_DETECT_PIN); + const bool unlocked = !digitalRead(SAFELOCK_DETECT_PIN); + const bool opened = digitalRead(DOOR_DETECT_PIN); + static Debounce Finger(finger); + static Debounce Unlocked(unlocked); + static Debounce Opened(opened); - g_Main.OnFingerInterrupt(!status); + int8_t fingerEdge = Finger.debounce(finger); + if(fingerEdge) + g_Main.OnFinger(fingerEdge & 1); + + int8_t unlockedEdge = Unlocked.debounce(unlocked); + if(unlockedEdge) + g_Main.OnLock(unlockedEdge & 1); + + int8_t openedEdge = Finger.debounce(opened); + if(openedEdge) + g_Main.OnDoor(openedEdge & 1); + + procTimerLoops++; + if(procTimerLoops > 25) // 250ms + procTimer.stop(); +} + +void IRAM_ATTR OnLevelChangeISR() +{ + procTimerLoops = 0; + procTimer.start(); } void ready() { debugf("READY!"); - gpio_pin_wakeup_enable(GPIO_ID_PIN(FINGER_DETECT_PIN), GPIO_PIN_INTR_LOLEVEL); - g_Main.Init(Serial); - attachInterrupt(FINGER_DETECT_PIN, OnFingerInterrupt, CHANGE); + gpio_pin_wakeup_enable(GPIO_ID_PIN(FINGER_DETECT_PIN), GPIO_PIN_INTR_LOLEVEL); + gpio_pin_wakeup_enable(GPIO_ID_PIN(SAFELOCK_DETECT_PIN), GPIO_PIN_INTR_LOLEVEL); + gpio_pin_wakeup_enable(GPIO_ID_PIN(DOOR_DETECT_PIN), GPIO_PIN_INTR_HILEVEL); + + attachInterrupt(FINGER_DETECT_PIN, OnLevelChangeISR, CHANGE); + attachInterrupt(SAFELOCK_DETECT_PIN, OnLevelChangeISR, CHANGE); + attachInterrupt(DOOR_DETECT_PIN, OnLevelChangeISR, CHANGE); + + procTimer.initializeMs<10>(OnProcTimer); } void init() @@ -45,7 +78,7 @@ void init() pinMode(FINGER_DETECT_PIN, INPUT); pinMode(SAFELOCK_DETECT_PIN, INPUT); - pinMode(DOOR_DETECT_PIN, INPUT); + pinMode(DOOR_DETECT_PIN, INPUT_PULLUP); // mount spiffs spiffs_mount(); diff --git a/app/main.cpp b/app/main.cpp index 3fd98fd..3f7bd84 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,6 +1,10 @@ #include +#include #include #include +#include +#include +#include #include "utils.h" #include "main.h" @@ -10,17 +14,98 @@ CMain::CMain() : m_FingerLogic(this) { } -static void STAGotIP(IpAddress ip, IpAddress mask, IpAddress gateway) +static void fileUploadMapper(HttpFiles& files) { - debugf("GOTIP - IP: %s, MASK: %s, GW: %s\n", ip.toString().c_str(), mask.toString().c_str(), - gateway.toString().c_str()); + files["firmware"] = new OtaUpgradeStream; } -static void STADisconnect(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) +static int onMessageDelivered(MqttClient& client, mqtt_message_t* message) { + Serial1 << _F("Message with id ") << message->puback.message_id << _F(" and QoS ") << message->puback.qos + << _F(" was delivered successfully.") << endl; + return 0; +} + +// Callback for messages, arrived from MQTT server +static int onMessageReceived(MqttClient& client, mqtt_message_t* message) +{ + Serial1 << _F("Received: ") << MqttBuffer(message->publish.topic_name) << ':' << endl; + Serial1 << '\t' << MqttBuffer(message->publish.content) << endl; + return 0; +} + +void CMain::OnStationGotIP(IpAddress ip, IpAddress mask, IpAddress gateway) +{ + m_StationConnected = true; + debugf("GOTIP - IP: %s, MASK: %s, GW: %s\n", ip.toString().c_str(), mask.toString().c_str(), gateway.toString().c_str()); + StartMqttClient(); +} + +void CMain::OnStationDisconnect(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) +{ + m_StationConnected = false; debugf("DISCONNECT - SSID: %s, REASON: %d", ssid.c_str(), WifiEvents.getDisconnectReasonDesc(reason).c_str()); } +int CMain::MqttOnConnect(MqttClient& client, mqtt_message_t* message) +{ + debugf("MQTT Connected!"); + + MqttSendMessage("safeweb/status", "online"); + + MqttSendDescription(); + return 0; +} + +void CMain::MqttOnDisconnect(TcpClient& client, bool flag) +{ + if(flag == true) + debugf("MQTT Broker Disconnected!!"); + else + debugf("MQTT Broker Unreachable!!"); + + // Restart connection attempt after few seconds + if(!m_StationConnected) + m_MqttTimer.initializeMs(2 * 1000, TimerDelegate(&CMain::StartMqttClient, this)).start(); +} + +void CMain::MqttSendDescription() +{ + if(m_Mqtt.getConnectionState() != eTCS_Connected) { + StartMqttClient(); // Auto reconnect + } +} + +void CMain::MqttSendMessage(const char *topic, const char *msg) +{ + if(m_Mqtt.getConnectionState() != eTCS_Connected) { + StartMqttClient(); // Auto reconnect + } + + m_Mqtt.publish(topic, msg); +} + +void CMain::StartMqttClient() +{ + m_MqttTimer.stop(); + if(!m_StationConnected || !Settings().m_MqttURL.Port || !Settings().m_MqttURL.Host) + return; + + if(!m_Mqtt.setWill("safeweb/status", "offline", MqttClient::getFlags(MQTT_QOS_AT_LEAST_ONCE, MQTT_RETAIN_TRUE))) { + debugf("Unable to mqtt.setWill"); + } + + m_Mqtt.setEventHandler(MQTT_TYPE_PUBACK, onMessageDelivered); + + m_Mqtt.setConnectedHandler(MqttDelegate(&CMain::MqttOnConnect, this)); + + m_Mqtt.setCompleteDelegate(TcpClientCompleteDelegate(&CMain::MqttOnDisconnect, this)); + m_Mqtt.setMessageHandler(onMessageReceived); + + m_Mqtt.connect(Settings().m_MqttURL, Settings().m_aMqttName); +} + + void CMain::Init(HardwareSerial &serial) { m_Settings.Load(); @@ -45,27 +130,61 @@ void CMain::Init(HardwareSerial &serial) WifiAccessPoint.enable(true); } - WifiEvents.onStationGotIP(STAGotIP); - WifiEvents.onStationDisconnect(STADisconnect); + WifiEvents.onStationGotIP(StationGotIPDelegate(&CMain::OnStationGotIP, this)); + WifiEvents.onStationDisconnect(StationDisconnectDelegate(&CMain::OnStationDisconnect, this)); m_FTP.listen(21); m_FTP.addUser(m_Settings.m_aUsername, m_Settings.m_aPassword); + HttpServerSettings settings; + settings.closeOnContentError = false; + settings.keepAliveSeconds = 5; + + m_HttpServer.configure(settings); + m_HttpServer.setBodyParser(MIME_JSON, bodyToStringParser); + m_HttpServer.setBodyParser(MIME_FORM_MULTIPART, formMultipartParser); m_HttpServer.listen(80); - m_HttpServer.setBodyParser("application/json", bodyToStringParser); m_HttpServer.paths.set("/api", HttpPathDelegate(&CMain::HttpOnApi, this)); + m_HttpServer.paths.set("/api/state", HttpPathDelegate(&CMain::HttpOnApi, this)); m_HttpServer.paths.set("/api/dashboard", HttpPathDelegate(&CMain::HttpOnApi, this)); m_HttpServer.paths.set("/api/fingerprint", HttpPathDelegate(&CMain::HttpOnApi, this)); m_HttpServer.paths.set("/api/fingerprint/label", HttpPathDelegate(&CMain::HttpOnApi, this)); m_HttpServer.paths.set("/api/fingerprint/delete", HttpPathDelegate(&CMain::HttpOnApi, this)); m_HttpServer.paths.set("/api/fingerprint/enroll", HttpPathDelegate(&CMain::HttpOnApi, this)); + m_HttpServer.paths.set("/api/fingerprint/security", HttpPathDelegate(&CMain::HttpOnApi, this)); m_HttpServer.paths.set("/api/unlock", HttpPathDelegate(&CMain::HttpOnApi, this)); + m_HttpServer.paths.set("/api/reset", HttpPathDelegate(&CMain::HttpOnApi, this)); + m_HttpServer.paths.set("/upgrade", new HttpMultipartResource(fileUploadMapper, HttpResourceDelegate(&CMain::HttpOnUpload, this))); m_HttpServer.paths.setDefault(HttpPathDelegate(&CMain::HttpOnFile, this)); m_FingerPrint.Init(serial, 0xFFFFFFFF, 0x00000000); m_FingerLogic.Init(&m_FingerPrint); + + m_LightSleepTimer.initializeMs(60 * 1000, TimerDelegate(&CMain::EnterLightSleep, this)); +} + +static void wakeupCallback() { + debugf("Wakeing up @ %lu", millis()); + debugf("Wakeing up @ %s", SystemClock.getSystemTimeString().c_str()); + wifi_fpm_close(); + wifi_set_opmode(STATION_MODE); + wifi_station_connect(); + system_soft_wdt_feed(); +} + +void CMain::EnterLightSleep() +{ + debugf("Going to sleep @ %lu", millis()); + debugf("Going to sleep @ %s", SystemClock.getSystemTimeString().c_str()); + wifi_station_disconnect(); + wifi_set_opmode(NULL_MODE); + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + wifi_fpm_open(); + wifi_fpm_set_wakeup_cb(wakeupCallback); + wifi_fpm_do_sleep(0xFFFFFFF); + system_soft_wdt_feed(); } bool CMain::HttpAuthorized(HttpRequest &request, HttpResponse &response) @@ -124,7 +243,6 @@ void CMain::HttpOnApi(HttpRequest &request, HttpResponse &response) return; } - HttpStatus status = HandleApi(request.method, endpoint, jsonReq, jsonResp); if(status != HTTP_STATUS_OK) { @@ -140,73 +258,96 @@ void CMain::HttpOnApi(HttpRequest &request, HttpResponse &response) HttpStatus CMain::HandleApi(HttpMethod method, String endpoint, JsonDocument &req, JsonDocument &resp) { - String test; - serializeJsonPretty(req, test); - - debugf("request: %s\n", test.c_str()); - - if(endpoint == "dashboard") + if(endpoint == "state" || endpoint == "dashboard") { if(method != HTTP_GET) return HTTP_STATUS_METHOD_NOT_ALLOWED; - JsonObject lock = resp.createNestedObject("lock"); - lock["locked"] = true; + JsonObject state = resp.createNestedObject("state"); + state["unlocked"] = (bool)!digitalRead(SAFELOCK_DETECT_PIN); + state["opened"] = (bool)digitalRead(DOOR_DETECT_PIN); + state["battery"] = (system_adc_read() / 1024.f) / 0.237; - JsonObject door = resp.createNestedObject("door"); - door["closed"] = true; - - JsonObject battery = resp.createNestedObject("battery"); - debugf("adc: %d\n", system_adc_read()); - battery["voltage"] = (system_adc_read() / 1024.f) / 0.23; - battery["color"] = "success"; - if(battery["voltage"] < 3.6f) - battery["color"] = "warning"; - - JsonObject network = resp.createNestedObject("network"); - if(WifiStation.isEnabled()) + if(endpoint == "dashboard") { - network["type"] = "Station"; - network["ssid"] = WifiStation.getSSID(); - network["channel"] = WifiStation.getChannel(); - network["dhcp"] = WifiStation.isEnabledDHCP(); - network["rssi"] = WifiStation.getRssi(); - network["signal"] = Rssi2Quality(WifiStation.getRssi()); - network["address"] = WifiStation.getIP().toString(); - } - else - { - network["type"] = "Access Point"; - network["ssid"] = WifiAccessPoint.getSSID(); - network["channel"] = WifiStation.getChannel(); - network["dhcp"] = true; - network["address"] = WifiAccessPoint.getIP().toString(); + JsonObject network = resp.createNestedObject("network"); + if(WifiStation.isEnabled()) + { + network["type"] = "Station"; + network["ssid"] = WifiStation.getSSID(); + network["channel"] = WifiStation.getChannel(); + network["dhcp"] = WifiStation.isEnabledDHCP(); + network["rssi"] = WifiStation.getRssi(); + network["signal"] = Rssi2Quality(network["rssi"]); + network["address"] = WifiStation.getIP().toString(); + } + else + { + network["type"] = "Access Point"; + network["ssid"] = WifiAccessPoint.getSSID(); + network["channel"] = WifiStation.getChannel(); + network["dhcp"] = true; + network["address"] = WifiAccessPoint.getIP().toString(); + } } } else if(endpoint == "unlock") { if(method != HTTP_POST) return HTTP_STATUS_METHOD_NOT_ALLOWED; - LockUnlock(); - resp["success"] = "true"; + if(!req.containsKey("unlock")) + return HTTP_STATUS_BAD_REQUEST; + + if(req["unlock"]) + LockUnlock(); + } + else if(endpoint == "reset") + { + if(method != HTTP_POST) return HTTP_STATUS_METHOD_NOT_ALLOWED; + + if(!req.containsKey("reset")) + return HTTP_STATUS_BAD_REQUEST; + + if(req["reset"]) + System.restart(500); } else if(endpoint == "fingerprint") { - if(method != HTTP_GET) return HTTP_STATUS_METHOD_NOT_ALLOWED; - - JsonArray fingerprints = resp.createNestedArray("fingerprints"); - uint16_t tmp = Settings().m_FingerPrints.count(); - for(uint16_t i = 0; i < tmp; i++) + if(method == HTTP_GET) { - JsonObject obj = fingerprints.createNestedObject(); - const CSettings::CFingerPrint &finger = Settings().m_FingerPrints.valueAt(i); + JsonArray fingerprints = resp.createNestedArray("fingerprints"); + uint16_t tmp = Settings().m_FingerPrints.count(); + for(uint16_t i = 0; i < tmp; i++) + { + JsonObject obj = fingerprints.createNestedObject(); + const CSettings::CFingerPrint &finger = Settings().m_FingerPrints.valueAt(i); - obj["num"] = finger.m_FingerNum; - obj["label"] = String(finger.m_aLabel); + obj["num"] = finger.m_FingerNum; + obj["label"] = String(finger.m_aLabel); - char aHexDigest[SHA256_SIZE*2+1]; - bytes2hex(finger.m_aDigest, sizeof(finger.m_aDigest), aHexDigest, sizeof(aHexDigest)); - obj["digest"] = String(aHexDigest); + char aHexDigest[SHA256_SIZE*2+1]; + bytes2hex(finger.m_aDigest, sizeof(finger.m_aDigest), aHexDigest, sizeof(aHexDigest)); + obj["digest"] = String(aHexDigest); + } + resp["securityLevel"] = Settings().m_SecurityLevel; } + else if(method == HTTP_POST) + { + if(!req.containsKey("securityLevel")) + return HTTP_STATUS_BAD_REQUEST; + + int newLevel = req["securityLevel"].as(); + if(newLevel > FINGERPRINT_SECURITY_LEVEL_5 || newLevel < FINGERPRINT_SECURITY_LEVEL_1) + return HTTP_STATUS_BAD_REQUEST; + + if(newLevel != Settings().m_SecurityLevel) + { + Settings().m_SecurityLevel = newLevel; + Settings().Save(); + FingerLogic().SetSecurityLevel(newLevel); + } + } + else + return HTTP_STATUS_METHOD_NOT_ALLOWED; } else if(endpoint == "fingerprint/label") { @@ -224,8 +365,6 @@ HttpStatus CMain::HandleApi(HttpMethod method, String endpoint, JsonDocument &re CSettings::CFingerPrint &finger = Settings().m_FingerPrints.valueAt(index); strncpy(finger.m_aLabel, label.c_str(), sizeof(finger.m_aLabel)); Settings().Save(); - - resp["success"] = true; } else if(endpoint == "fingerprint/delete") { @@ -243,8 +382,6 @@ HttpStatus CMain::HandleApi(HttpMethod method, String endpoint, JsonDocument &re FingerPrint().DeleteTemplate(finger.m_FingerNum, 1); Settings().m_FingerPrints.removeAt(index); Settings().Save(); - - resp["success"] = true; } else if(endpoint == "fingerprint/enroll") { @@ -254,7 +391,7 @@ HttpStatus CMain::HandleApi(HttpMethod method, String endpoint, JsonDocument &re { if(req["cancel"].as() && m_Enrolling) { - resp["success"] = FingerLogic().EnrollFinger(false); + FingerLogic().EnrollFinger(false); m_Enrolling = false; m_Enrolled = false; } @@ -336,15 +473,100 @@ void CMain::HttpOnFile(HttpRequest &request, HttpResponse &response) response.sendFile(file); } -void CMain::OnFingerInterrupt(bool finger) +int CMain::HttpOnUpload(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response) { - m_FingerLogic.OnFingerInterrupt(finger); + if(!HttpAuthorized(request, response)) + return 1; + + ReadWriteStream* file = request.files["firmware"]; + auto otaStream = static_cast(file); + if(otaStream == nullptr) { + debug_e("Something went wrong with the file upload"); + return 1; + } + + if(response.isSuccess() && !otaStream->hasError()) { + // defer the reboot by 1000 milliseconds to give time to the web server to return the response + System.restart(1000); + + response.sendFile("otadone.html"); + response.headers[HTTP_HEADER_CONNECTION] = "close"; + + return 0; + } + + response.code = HTTP_STATUS_BAD_REQUEST; + response.setContentType(MIME_HTML); + String html = toString(otaStream->errorCode); + response.headers[HTTP_HEADER_CONTENT_LENGTH] = html.length(); + response.sendString(html); + + return 0; } -void CMain::FingerEnable(bool enable) +void CMain::CheckSleep() +{ + if(!m_FingerPlaced && + !m_LockUnlocked && + !m_DoorOpened) + { + m_LightSleepTimer.startOnce(); + } + else + { + m_LightSleepTimer.stop(); + } +} + +void CMain::OnFinger(bool finger) +{ + m_FingerPlaced = finger; + m_FingerLogic.OnFinger(finger); + + if(finger) + MqttSendMessage("safeweb/finger/placed", "true"); + else + MqttSendMessage("safeweb/finger/placed", "false"); + CheckSleep(); +} + +void CMain::OnLock(bool unlocked) +{ + m_LockUnlocked = unlocked; + + if(unlocked) + MqttSendMessage("safeweb/lock/unlocked", "true"); + else + MqttSendMessage("safeweb/lock/unlocked", "false"); + CheckSleep(); +} + +void CMain::OnDoor(bool opened) +{ + m_DoorOpened = opened; + + if(opened) + MqttSendMessage("safeweb/door/opened", "true"); + else + MqttSendMessage("safeweb/door/opened", "false"); + CheckSleep(); +} + +void CMain::FingerPower(bool enable) { const int pin = FINGER_ENABLE_PIN; digitalWrite(pin, !enable); + + if(enable) + { + wifi_set_sleep_level(MAX_SLEEP_T); + wifi_set_listen_interval(3); + wifi_set_sleep_type(MODEM_SLEEP_T); + } + else + { + wifi_set_sleep_type(LIGHT_SLEEP_T); + } } void CMain::LockSendBytes(uint8_t *pBytes, uint8_t len) @@ -443,11 +665,6 @@ void CMain::OnFingerEnrolled(uint16_t fingerNum, uint8_t digest[SHA256_SIZE]) bytes2hex(finger.m_aDigest, sizeof(finger.m_aDigest), aHexDigest, sizeof(aHexDigest)); debugf("OnFingerEnrolled: \"%s\"", aHexDigest); - Serial1.printf("(sz: %d) Finger hexdigest: ", sizeof(finger.m_aDigest)); - for(uint8_t i = 0; i < sizeof(finger.m_aDigest); i++) - Serial1.printf("%x", finger.m_aDigest[i]); - Serial1.printf("\n"); - Settings().m_FingerPrints[fingerNum] = finger; Settings().Save(); m_Enrolled = true; diff --git a/app/main.h b/app/main.h index 3e6143a..4f6569d 100644 --- a/app/main.h +++ b/app/main.h @@ -19,10 +19,19 @@ class CMain public: CMain(); void Init(HardwareSerial &serial); + void CheckSleep(); + void EnterLightSleep(); - void OnFingerInterrupt(bool finger); + void OnStationGotIP(IpAddress ip, IpAddress mask, IpAddress gateway); + void OnStationDisconnect(const String& ssid, MacAddress bssid, WifiDisconnectReason reason); + int MqttOnConnect(MqttClient& client, mqtt_message_t* message); + void MqttOnDisconnect(TcpClient& client, bool flag); - void FingerEnable(bool enable); + void OnFinger(bool finger); + void OnLock(bool unlocked); + void OnDoor(bool opened); + + void FingerPower(bool enable); void LockUnlock(); void EnrollMessage(const char *msg, bool error=false); @@ -38,9 +47,14 @@ private: bool HttpAuthorized(HttpRequest &request, HttpResponse &response); void HttpOnApi(HttpRequest &request, HttpResponse &response); void HttpOnFile(HttpRequest &request, HttpResponse &response); + int HttpOnUpload(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response); HttpStatus HandleApi(HttpMethod method, String endpoint, JsonDocument &req, JsonDocument &resp); + void StartMqttClient(); + void MqttSendDescription(); + void MqttSendMessage(const char *topic, const char *msg); + private: void LockSendBytes(uint8_t *pBytes, uint8_t len); void LockSendCode(uint8_t code[8]); @@ -51,12 +65,21 @@ private: FtpServer m_FTP; HttpServer m_HttpServer; + MqttClient m_Mqtt; + Timer m_MqttTimer; + Timer m_LightSleepTimer; String m_EnrollMessage; String m_EnrollLabel; CSettings::CFingerPrint m_EnrolledFinger; bool m_Enrolling; bool m_Enrolled; + + bool m_StationConnected; + + bool m_FingerPlaced; + bool m_LockUnlocked; + bool m_DoorOpened; }; extern CMain g_Main; diff --git a/app/utils.cpp b/app/utils.cpp index d082b36..c42e715 100644 --- a/app/utils.cpp +++ b/app/utils.cpp @@ -73,3 +73,32 @@ int Rssi2Quality(sint8 rssi) else return 4; } + +Debounce::Debounce() : state(0xFF) {} +Debounce::Debounce(bool signal) { init(signal); } +void Debounce::init(bool signal) +{ + if(signal) + state = 0xFF; + else + state = 0x00; +} + +int8_t Debounce::debounce(bool signal) +{ + const uint8_t current = state & UPPER; + const uint8_t history = (state << 1) & LOWER; + + state = current | history | signal; + + // Events are triggered when the history is saturated + // with the opposite of the active switch state. + // As a result, the events are guaranteed to alternate. + + switch (state) { + case UPPER: state = 0x00; return -1; // LOW/False (falling edge) + case LOWER: state = 0xFF; return 1; // HIGH/True (rising edge) + } + + return 0;//state & UPPER; +} diff --git a/app/utils.h b/app/utils.h index d0ed894..8d9697d 100644 --- a/app/utils.h +++ b/app/utils.h @@ -5,4 +5,22 @@ int hex2bytes(const char *str, uint8_t *bytes, int32_t length); void bytes2hex(const uint8_t *bytes, int32_t length, char *str, int32_t strLength); int Rssi2Quality(sint8 rssi); +class Debounce +{ + static constexpr uint8_t UPPER = 0b10000000; + static constexpr uint8_t LOWER = 0b01111111; +public: + Debounce(); + Debounce(bool signal); + void init(bool signal); + /* Return value: + * 0: no change + * -1: LOW/False (falling edge) + * 1: HIGH/True (rising edge) + */ + int8_t debounce(bool signal); +private: + uint8_t state; +}; + #endif diff --git a/component.mk b/component.mk index dcb4953..cfff8c6 100644 --- a/component.mk +++ b/component.mk @@ -1,4 +1,11 @@ -ARDUINO_LIBRARIES := ArduinoJson6 +ARDUINO_LIBRARIES := ArduinoJson6 MultipartParser OtaUpgrade -HWCONFIG = spiffs +HWCONFIG = spiffs-two-roms SPIFF_FILES = files + +ifndef MAKE_DOCS + +web-upload: spiffs-image-update + $(call WriteFlash,$(SPIFF_START_ADDR)=$(SPIFF_BIN_OUT)) + +endif diff --git a/files/favicon.ico b/files/favicon.ico deleted file mode 100644 index 23ceec5..0000000 Binary files a/files/favicon.ico and /dev/null differ diff --git a/files/favicon.ico.gz b/files/favicon.ico.gz new file mode 100644 index 0000000..140b70d Binary files /dev/null and b/files/favicon.ico.gz differ diff --git a/files/index.html b/files/index.html deleted file mode 100644 index 1c18dbe..0000000 --- a/files/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - Safe control panel - - - - - - - -
- - - - - - - - - - diff --git a/files/index.html.gz b/files/index.html.gz new file mode 100644 index 0000000..a7a989f Binary files /dev/null and b/files/index.html.gz differ diff --git a/files/main.css.gz b/files/main.css.gz index 772ab62..69b0b75 100644 Binary files a/files/main.css.gz and b/files/main.css.gz differ diff --git a/files/main.js.gz b/files/main.js.gz index 8044855..9629bd8 100644 Binary files a/files/main.js.gz and b/files/main.js.gz differ diff --git a/files/otadone.html.gz b/files/otadone.html.gz new file mode 100644 index 0000000..cbe8466 Binary files /dev/null and b/files/otadone.html.gz differ diff --git a/files/settings.conf b/files/settings.conf index 99c40d7..e4ad423 100644 --- a/files/settings.conf +++ b/files/settings.conf @@ -10,6 +10,13 @@ "netmask": "0.0.0.0", "gateway": "0.0.0.0" }, + "mqtt": { + "client_name": "safeweb", + "host": "", + "port": 0, + "username": "safeweb", + "password": "password" + }, "lock_code": [ 0, 1, @@ -21,5 +28,6 @@ 7 ], "fingerprints": [ - ] + ], + "security_level": 4 } \ No newline at end of file diff --git a/files/templates.js.gz b/files/templates.js.gz deleted file mode 100644 index ff7a6ba..0000000 Binary files a/files/templates.js.gz and /dev/null differ diff --git a/files/wifi-sprites.png b/files/wifi-sprites.png.gz similarity index 96% rename from files/wifi-sprites.png rename to files/wifi-sprites.png.gz index 863d0d7..53e078f 100644 Binary files a/files/wifi-sprites.png and b/files/wifi-sprites.png.gz differ