TTL Reader Support
This commit is contained in:
parent
33db93deed
commit
74cc87fe65
8 changed files with 255 additions and 143 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -49,6 +49,7 @@
|
|||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
"typeinfo": "cpp",
|
||||
"iostream": "cpp"
|
||||
}
|
||||
}
|
1
README
1
README
|
@ -10,7 +10,6 @@ This project is a card reader system for Techinc that uses a WIEGAND based reade
|
|||
-DWIFI : Enable WIFI and use secrets.h to manage.
|
||||
-DWEB_SERVER : Enable Web Server
|
||||
-DSERIAL_DEBUG : Enable Serial Console output and debug.
|
||||
-DWEB_SERIAL_DEBUG : Enable Web Serial console to monitor for issues (does not support auth, needs -DWEB_SERVER)
|
||||
-DNET_FAIL_SAFE : If WIFI disconnects release door / relay.
|
||||
-DWEB_OTA_UPDATE : Present Web Interface on /update for managing firmware over the air (needs -DWEB_SERVER)
|
||||
-DLOCAL_ACL : Enable local ACL list
|
||||
|
|
|
@ -2,32 +2,39 @@
|
|||
#define HARDWARE_H
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef WEB_SERVER
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
#include <WebSerial.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOARD1
|
||||
#define TAMPER_PIN 26
|
||||
#define LEDCTL_PIN 32
|
||||
#define DATA0_PIN 34
|
||||
#define DATA1_PIN 36
|
||||
#ifdef WG_READER
|
||||
#define TAMPER_PIN 26
|
||||
#define LEDCTL_PIN 32
|
||||
#define DATA0_PIN 34
|
||||
#define DATA1_PIN 36
|
||||
#endif
|
||||
|
||||
|
||||
#define RELAY1_PIN 32
|
||||
#define RELAY2_PIN 33
|
||||
#define RELAY_DELAY 3000
|
||||
#endif
|
||||
|
||||
#ifdef BOARD2
|
||||
#define TAMPER_PIN 0
|
||||
#define ALARM_PIN 33
|
||||
#define WIEGAND_PIN 32
|
||||
#define LEDCTL_PIN 25
|
||||
#define DATA0_PIN 26
|
||||
#define DATA1_PIN 27
|
||||
#ifdef WG_READER
|
||||
#define TAMPER_PIN 0
|
||||
#define ALARM_PIN 33
|
||||
#define LEDCTL_PIN 25
|
||||
#define DATA0_PIN 26
|
||||
#define DATA1_PIN 27
|
||||
#define BIT_MODE_WG34_PIN 32
|
||||
#endif
|
||||
|
||||
#ifdef TTL_READER
|
||||
#define TXD 17
|
||||
#define RXD 16
|
||||
|
||||
#endif
|
||||
|
||||
#define RELAY1_PIN 13
|
||||
#define RELAY_DELAY 3000
|
||||
#define BIT_MODE_WG34_PIN 32
|
||||
|
||||
#endif
|
||||
|
||||
void controlRelay();
|
||||
|
|
|
@ -18,14 +18,17 @@
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef TTL_READER
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER
|
||||
#include <AsyncTCP.h>
|
||||
#include "ESPAsyncWebServer.h"
|
||||
#include "SPIFFS.h"
|
||||
#include <AsyncJson.h>
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
#include <WebSerial.h>
|
||||
#endif
|
||||
#ifdef WEB_OTA_UPDATE
|
||||
#include <AsyncElegantOTA.h>
|
||||
#endif
|
||||
|
|
11
src/ACL.cpp
11
src/ACL.cpp
|
@ -79,26 +79,17 @@ bool ACL::validateAccess(const String& cardId) {
|
|||
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("Checking ACL match for Card: " + String(cardId) + " Against Card: " + String(acl[i].cardId) + " desc: " + String(acl[i].desc));
|
||||
#endif
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.println("Checking ACL match for Card: " + String(cardId) + " Against Card: " + String(acl[i].cardId) + " desc: " + String(acl[i].desc));
|
||||
#endif
|
||||
#endif
|
||||
if (acl[i].cardId.equals(cardId)) {
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("Card matched and authenticated.");
|
||||
#endif
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.println("Card matched and authenticated.");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("Card did not match.");
|
||||
#endif
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.println("Card did not match.");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,6 @@ void unlockDoor(bool silent) {
|
|||
digitalWrite(LEDCTL_PIN,LOW);
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.println("door unlocked");
|
||||
#endif
|
||||
}
|
||||
|
||||
void lockDoor(bool silent) {
|
||||
|
@ -50,10 +47,6 @@ void lockDoor(bool silent) {
|
|||
#ifdef LEDCTL_PIN
|
||||
digitalWrite(LEDCTL_PIN,HIGH);
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.println("door locked");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,5 +80,6 @@ String stateDoor() {
|
|||
return "Locked";
|
||||
}
|
||||
#endif
|
||||
return ""; // Add a return statement to handle the case when RELAY1 is not defined
|
||||
}
|
||||
|
||||
|
|
298
src/main.cpp
298
src/main.cpp
|
@ -368,6 +368,13 @@ void setup() {
|
|||
Serial.begin(9600);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TTL_READER
|
||||
Serial2.begin(9600, SERIAL_8N1, RXD, TXD);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER
|
||||
WiFi.disconnect(true);
|
||||
#endif
|
||||
|
@ -396,14 +403,15 @@ void setup() {
|
|||
AsyncElegantOTA.begin(&server, http_username, http_password);
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.begin(&server);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DATA0_PIN
|
||||
pinMode(DATA0_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
|
||||
pinMode(DATA0_PIN, INPUT_PULLUP);
|
||||
pinMode(DATA1_PIN, INPUT_PULLUP);
|
||||
#ifdef DATA1_PIN
|
||||
pinMode(DATA1_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
|
||||
#ifdef BIT_MODE_WG34
|
||||
pinMode(BIT_MODE_WG34_PIN, OUTPUT);
|
||||
|
@ -415,11 +423,15 @@ void setup() {
|
|||
#endif
|
||||
|
||||
#ifdef RELAY1
|
||||
pinMode(RELAY1_PIN, OUTPUT);
|
||||
#ifdef RELAY1_PIN
|
||||
pinMode(RELAY1_PIN, OUTPUT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(DATA0_PIN), handleData0Interrupt, FALLING);
|
||||
attachInterrupt(digitalPinToInterrupt(DATA1_PIN), handleData1Interrupt, FALLING);
|
||||
#ifdef WG_READER
|
||||
attachInterrupt(digitalPinToInterrupt(DATA0_PIN), handleData0Interrupt, FALLING);
|
||||
attachInterrupt(digitalPinToInterrupt(DATA1_PIN), handleData1Interrupt, FALLING);
|
||||
#endif
|
||||
|
||||
#ifdef WIFI
|
||||
WiFi.onEvent(WiFiStationConnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED);
|
||||
|
@ -440,8 +452,10 @@ void setup() {
|
|||
#endif
|
||||
|
||||
#ifdef BUZZER
|
||||
pinMode(ALARM_PIN, OUTPUT);
|
||||
digitalWrite(ALARM_PIN, HIGH); // Do not set to low or it will constantly beep.
|
||||
#ifdef ALARM_PIN
|
||||
pinMode(ALARM_PIN, OUTPUT);
|
||||
digitalWrite(ALARM_PIN, HIGH); // Do not set to low or it will constantly beep.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER
|
||||
|
@ -652,30 +666,120 @@ void setup() {
|
|||
* It then calls the appropriate functions based on the defined macros to handle the card data.
|
||||
* If no valid card data is received within the specified time, it resets the card data and bit count.
|
||||
*
|
||||
* @note This function assumes the availability of certain macros like TINANCE2_BACKEND, LOCAL_ACL, SERIAL_ACL, SERIAL_DEBUG, and WEB_SERIAL_DEBUG.
|
||||
* @note This function assumes the availability of certain macros like TINANCE2_BACKEND, LOCAL_ACL, SERIAL_ACL and SERIAL_DEBUG.
|
||||
*
|
||||
* @note This function assumes the availability of certain variables like newDataAvailable, lastDataTime, displayDelay, cardData, bitCount, and maxReaderWaitTime.
|
||||
*
|
||||
* @note This function assumes the availability of certain functions like updateDoorStatus, checkSerialCommand, tinance2authrequest, and localAcl.
|
||||
*/
|
||||
void loop() {
|
||||
#ifdef TINANCE2_BACKEND
|
||||
updateDoorStatus();
|
||||
#endif
|
||||
|
||||
#ifdef LOCAL_ACL
|
||||
#ifdef SERIAL_ACL
|
||||
checkSerialCommand();
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TTL_READER
|
||||
String parseStringSTXandETX(const String& incoming) {
|
||||
int stxPos = incoming.indexOf('\x02');
|
||||
int etxPos = incoming.indexOf('\x03');
|
||||
|
||||
if (newDataAvailable) {
|
||||
newDataAvailable = false;
|
||||
lastDataTime = millis(); // Reset the time of last received data
|
||||
if (stxPos == -1 || etxPos == -1) {
|
||||
return "";
|
||||
}
|
||||
String parsedString = incoming.substring(stxPos + 1, etxPos);
|
||||
// Remove whitespace and hidden characters
|
||||
parsedString.replace(" ", "");
|
||||
parsedString.replace("\t", "");
|
||||
parsedString.replace("\n", "");
|
||||
parsedString.replace("\r", "");
|
||||
|
||||
return parsedString;
|
||||
}
|
||||
uint64_t hexToBinary(const String& hexString) {
|
||||
String binaryString;
|
||||
for (char c : hexString) {
|
||||
switch (c) {
|
||||
case '0':
|
||||
binaryString += "0000";
|
||||
break;
|
||||
case '1':
|
||||
binaryString += "0001";
|
||||
break;
|
||||
case '2':
|
||||
binaryString += "0010";
|
||||
break;
|
||||
case '3':
|
||||
binaryString += "0011";
|
||||
break;
|
||||
case '4':
|
||||
binaryString += "0100";
|
||||
break;
|
||||
case '5':
|
||||
binaryString += "0101";
|
||||
break;
|
||||
case '6':
|
||||
binaryString += "0110";
|
||||
break;
|
||||
case '7':
|
||||
binaryString += "0111";
|
||||
break;
|
||||
case '8':
|
||||
binaryString += "1000";
|
||||
break;
|
||||
case '9':
|
||||
binaryString += "1001";
|
||||
break;
|
||||
case 'A':
|
||||
case 'a':
|
||||
binaryString += "1010";
|
||||
break;
|
||||
case 'B':
|
||||
case 'b':
|
||||
binaryString += "1011";
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
binaryString += "1100";
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
binaryString += "1101";
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
binaryString += "1110";
|
||||
break;
|
||||
case 'F':
|
||||
case 'f':
|
||||
binaryString += "1111";
|
||||
break;
|
||||
default:
|
||||
// Invalid hexadecimal digit
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.print("Invalid Hex Char: ");
|
||||
Serial.println(c);
|
||||
Serial.print("Hex String: ");
|
||||
Serial.println(hexString);
|
||||
Serial.print("Hex Char: ");
|
||||
Serial.println(c);
|
||||
Serial.print("Binary String: ");
|
||||
Serial.println(binaryString);
|
||||
#endif
|
||||
return 0ULL;
|
||||
}
|
||||
}
|
||||
uint64_t binaryValue = 0ULL;
|
||||
for (char bit : binaryString) {
|
||||
binaryValue <<= 1;
|
||||
binaryValue |= (bit - '0');
|
||||
}
|
||||
|
||||
if (millis() - lastDataTime >= displayDelay && cardData != 0 && (bitCount == 26 || bitCount == 34)) {
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.print("Binary Value: ");
|
||||
Serial.println(binaryValue);
|
||||
#endif
|
||||
return binaryValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void authenticationFlow(uint64_t cardData) {
|
||||
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
|
||||
uint64_t cardID = (cardData >> 1) & 0xFFFF;
|
||||
|
||||
|
@ -695,22 +799,7 @@ void loop() {
|
|||
Serial.print("Total Bits Received: ");
|
||||
Serial.println(bitCount);
|
||||
#endif
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.print("Facility ID (Decimal): ");
|
||||
WebSerial.println(facilityID);
|
||||
WebSerial.print("Facility ID (Binary): ");
|
||||
WebSerial.println(facilityID, BIN);
|
||||
|
||||
WebSerial.print("Card ID (Decimal): ");
|
||||
WebSerial.println(cardID);
|
||||
WebSerial.print("Card ID (Binary): ");
|
||||
WebSerial.println(cardID, BIN);
|
||||
|
||||
WebSerial.print("Card Data (Binary): ");
|
||||
WebSerial.println(cardData, BIN);
|
||||
WebSerial.print("Total Bits Received: ");
|
||||
WebSerial.println(bitCount);
|
||||
#endif
|
||||
|
||||
String fullCardID = String(facilityID)+":"+String(cardID);
|
||||
|
||||
#ifdef SERIAL_DEBUG
|
||||
|
@ -718,10 +807,6 @@ void loop() {
|
|||
Serial.println(fullCardID);
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.print("Full Card (Tinance2): ");
|
||||
WebSerial.println(fullCardID);
|
||||
#endif
|
||||
|
||||
#ifdef TINANCE2_BACKEND
|
||||
if (settings.getDoorDisabled()) {
|
||||
|
@ -739,52 +824,97 @@ void loop() {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
cardData = 0; // Reset the card data
|
||||
lastDataTime = millis(); // Reset the time of last received data
|
||||
bitCount = 0; // Reset the bit count
|
||||
}
|
||||
|
||||
}
|
||||
else if (millis() - lastDataTime >= maxReaderWaitTime && cardData != 0) {
|
||||
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
|
||||
uint64_t cardID = (cardData >> 1) & 0xFFFF;
|
||||
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("--- Reader Input Error ---");
|
||||
Serial.print("Facility ID (Decimal): ");
|
||||
Serial.println(facilityID);
|
||||
Serial.print("Facility ID (Binary): ");
|
||||
Serial.println(facilityID, BIN);
|
||||
|
||||
Serial.print("Card ID (Decimal): ");
|
||||
Serial.println(cardID);
|
||||
Serial.print("Card ID (Binary): ");
|
||||
Serial.println(cardID, BIN);
|
||||
|
||||
Serial.print("Card Data (Binary): ");
|
||||
Serial.println(cardData, BIN);
|
||||
Serial.print("Total Bits Received: ");
|
||||
Serial.println(bitCount);
|
||||
void loop() {
|
||||
#ifdef TINANCE2_BACKEND
|
||||
updateDoorStatus();
|
||||
#endif
|
||||
|
||||
#ifdef LOCAL_ACL
|
||||
#ifdef SERIAL_ACL
|
||||
checkSerialCommand();
|
||||
#endif
|
||||
#ifdef WEB_SERIAL_DEBUG
|
||||
WebSerial.print("Facility ID (Decimal): ");
|
||||
WebSerial.println(facilityID);
|
||||
WebSerial.print("Facility ID (Binary): ");
|
||||
WebSerial.println(facilityID, BIN);
|
||||
#endif
|
||||
|
||||
WebSerial.print("Card ID (Decimal): ");
|
||||
WebSerial.println(cardID);
|
||||
WebSerial.print("Card ID (Binary): ");
|
||||
WebSerial.println(cardID, BIN);
|
||||
|
||||
WebSerial.print("Card Data (Binary): ");
|
||||
WebSerial.println(cardData, BIN);
|
||||
WebSerial.print("Total Bits Received: ");
|
||||
WebSerial.println(bitCount);
|
||||
#endif
|
||||
|
||||
cardData = 0; // Reset the card data
|
||||
lastDataTime = millis(); // Reset the time of last received data
|
||||
bitCount = 0; // Reset the bit count
|
||||
#ifdef TTL_READER
|
||||
if (Serial2.available() > 0) {
|
||||
String incoming = Serial2.readString();
|
||||
String parsed = parseStringSTXandETX(incoming);
|
||||
|
||||
}
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.print("Message Received: ");
|
||||
Serial.println(incoming);
|
||||
#endif
|
||||
|
||||
if (parsed != "") {
|
||||
uint64_t cardData = hexToBinary(parsed);
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("Valid TTL Reader Data");
|
||||
Serial.print("I received: ");
|
||||
Serial.println(incoming);
|
||||
Serial.print(parsed);
|
||||
Serial.println("Hex Value:");
|
||||
Serial.print(cardData);
|
||||
#endif
|
||||
authenticationFlow(cardData);
|
||||
}
|
||||
else {
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("Invalid TTL Reader Data");
|
||||
Serial.print("I received: ");
|
||||
Serial.println(incoming);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef WG_READER
|
||||
if (newDataAvailable) {
|
||||
newDataAvailable = false;
|
||||
lastDataTime = millis(); // Reset the time of last received data
|
||||
}
|
||||
|
||||
if (millis() - lastDataTime >= displayDelay && cardData != 0 && (bitCount == 26 || bitCount == 34)) {
|
||||
|
||||
authenticationFlow(cardData);
|
||||
cardData = 0; // Reset the card data
|
||||
lastDataTime = millis(); // Reset the time of last received data
|
||||
bitCount = 0; // Reset the bit count
|
||||
|
||||
}
|
||||
else if (millis() - lastDataTime >= maxReaderWaitTime && cardData != 0) {
|
||||
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
|
||||
uint64_t cardID = (cardData >> 1) & 0xFFFF;
|
||||
|
||||
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.println("--- Reader Input Error ---");
|
||||
Serial.print("Facility ID (Decimal): ");
|
||||
Serial.println(facilityID);
|
||||
Serial.print("Facility ID (Binary): ");
|
||||
Serial.println(facilityID, BIN);
|
||||
|
||||
Serial.print("Card ID (Decimal): ");
|
||||
Serial.println(cardID);
|
||||
Serial.print("Card ID (Binary): ");
|
||||
Serial.println(cardID, BIN);
|
||||
|
||||
Serial.print("Card Data (Binary): ");
|
||||
Serial.println(cardData, BIN);
|
||||
Serial.print("Total Bits Received: ");
|
||||
Serial.println(bitCount);
|
||||
#endif
|
||||
|
||||
cardData = 0; // Reset the card data
|
||||
lastDataTime = millis(); // Reset the time of last received data
|
||||
bitCount = 0; // Reset the bit count
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,35 +1,21 @@
|
|||
#include "settings.h"
|
||||
|
||||
|
||||
Preferences settings_preferences;
|
||||
|
||||
Settings::Settings() {
|
||||
// Set default value for disableDoor
|
||||
disableDoor = false;
|
||||
#ifdef LATCH_DOOR
|
||||
doorMode = "LATCH"; // Set default value for doorMode
|
||||
#endif
|
||||
#ifdef TOGGLE_DOOR
|
||||
doorMode = "TOGGLE"; // Set default value for doorMode
|
||||
#endif
|
||||
Settings::Settings() : disableDoor(false), doorMode("LATCH") {
|
||||
}
|
||||
|
||||
void Settings::loadFromEEPROM() {
|
||||
settings_preferences.begin("settings");
|
||||
disableDoor = settings_preferences.getBool("disableDoor", false);
|
||||
#ifdef LATCH_DOOR
|
||||
doorMode = settings_preferences.getString("doorMode", "LATCH"); // Load doorMode from EEPROM
|
||||
#endif
|
||||
#ifdef TOGGLE_DOOR
|
||||
doorMode = settings_preferences.getString("doorMode", "TOGGLE"); // Load doorMode from EEPROM
|
||||
#endif
|
||||
doorMode = settings_preferences.getString("doorMode", "LATCH");
|
||||
settings_preferences.end();
|
||||
}
|
||||
|
||||
void Settings::saveToEEPROM() {
|
||||
settings_preferences.begin("settings");
|
||||
settings_preferences.putBool("disableDoor", disableDoor);
|
||||
settings_preferences.putString("doorMode", doorMode); // Save doorMode to EEPROM
|
||||
settings_preferences.putString("doorMode", doorMode);
|
||||
settings_preferences.end();
|
||||
}
|
||||
|
||||
|
@ -40,7 +26,7 @@ void Settings::setDisableDoor(bool value) {
|
|||
Serial.print("Settings::setDisableDoor: ");
|
||||
Serial.println(disableDoor);
|
||||
#endif
|
||||
saveToEEPROM(); // Save the setting immediately to Preferences
|
||||
saveToEEPROM();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,12 +40,13 @@ void Settings::setDoorMode(const String mode) {
|
|||
doorMode = mode;
|
||||
#ifdef SERIAL_DEBUG
|
||||
Serial.print("Settings::setDoorMode: ");
|
||||
Serial.println(doorMode.c_str());
|
||||
Serial.println(doorMode);
|
||||
#endif
|
||||
saveToEEPROM(); // Save the setting immediately to Preferences
|
||||
saveToEEPROM();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String Settings::getDoorMode() {
|
||||
return doorMode;
|
||||
}
|
Loading…
Reference in a new issue