diff --git a/esp32/CardReader.h b/esp32/CardReader.h new file mode 100644 index 0000000..fa6c226 --- /dev/null +++ b/esp32/CardReader.h @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include "alarm.h" +// #include +#include "Dict.h" +#include "Times.h" + + + + +// https://randomnerdtutorials.com/esp32-mfrc522-rfid-reader-arduino/ +MFRC522DriverPinSimple ss_pin(5); +class CardReader{ +private: + String user1="0438768a2c6a80"; + String user2="23141f2d"; + + MFRC522DriverSPI driver{ss_pin}; // Create SPI driver + //MFRC522DriverI2C driver{}; // Create I2C driver + MFRC522 mfrc522{driver}; // Create MFRC522 instance + AlarmStatus* status; + long lastCardRead =1; + bool doubleReaded=false; + bool initialized=false; + bool failed=false; + long restartAttempt=0; + long lastRestart=0; + + Dictionary &users = *(new Dictionary()); + + using PCD_Version = MFRC522Constants::PCD_Version; + using StatusCode = MFRC522Constants::StatusCode; +public: + CardReader(AlarmStatus* statusRef) + { + status = statusRef; + } + + void Init(){ + initialized = mfrc522.PCD_Init(); + if(!initialized) return; + Serial.print("Card Reader init: "); + MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); // Show details of PCD - MFRC522 Card Reader details. + lastRestart=millis(); + lastCardRead=millis(); + } + + void AddUser(String id, String name){ + users(id, name); + } + + bool IsInit(){ + return initialized; + } + + void HandleCard(){ + if(!initialized){ + return; + } + if(failed && restartAttempt + FromSeconds(2) < millis()){ + restartAttempt=millis(); + mfrc522.PCD_Reset(); + auto version = mfrc522.PCD_GetVersion(); + if(version == PCD_Version::Version_Unknown) { + Serial.println("restart attempt unsuccessful"); + return; + } + Serial.print("Card reader: Restart attempt ok: "); + MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); + failed=false; + mfrc522.PCD_Init(); + + return; + } + + if(failed){ + return; + } + + if(lastRestart + FromMinutes(5) < millis()){ + lastRestart =millis(); + mfrc522.PCD_Reset(); + if(!mfrc522.PCD_Init()){ + failed = true; + restartAttempt=millis(); + Serial.print("Card reader - Restart failure"); + return; + } + // Serial.print("Card reader - Restart ok: "); + MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); + return; + } + + if (!mfrc522.PICC_IsNewCardPresent()) { + return; + } + + if(lastCardRead + FromSeconds(1) > millis()) + { + doubleReaded=true; + return; + } + lastCardRead = millis(); + + // Select one of the cards. + if (!mfrc522.PICC_ReadCardSerial()) { + + auto sc = mfrc522.PICC_HaltA(); + if(sc == StatusCode::STATUS_ERROR){ + Serial.println("Connection with card reader failed"); + failed=true; + restartAttempt=millis(); + }else{ + Serial.println("Card Reader: Could not read"); + } + + status->showError =true; + return; + } + + // Dump debug info about the card; PICC_HaltA() is automatically called. + // MFRC522Debug::PICC_DumpToSerial(mfrc522, Serial, &(mfrc522.uid)); + + // Serial.print("Card UID: "); + // MFRC522Debug::PrintUID(Serial, (mfrc522.uid)); + // Serial.println(); + + // Save the UID on a String variable + String uidString = ""; + for (byte i = 0; i < mfrc522.uid.size; i++) { + if (mfrc522.uid.uidByte[i] < 0x10) { + uidString += "0"; + } + uidString += String(mfrc522.uid.uidByte[i], HEX); + } + Serial.print("Card Read: ");Serial.println(uidString); + + for (int i = 0; i < users.count(); i++) { + if(users(i) == uidString){ + status->allowed=true; + status->userAllowed=users[i]; + return; + } + } + + Serial.println("access not granted"); + status->showError =true; + } +}; diff --git a/esp32/Dict.h b/esp32/Dict.h new file mode 100644 index 0000000..6ad5575 --- /dev/null +++ b/esp32/Dict.h @@ -0,0 +1,7 @@ +#ifndef _DICTIONARY_H_ +#define _DICTIONARY_H_ +// #include "DictionaryDeclarations.h" +#include + + +#endif \ No newline at end of file diff --git a/esp32/LedController.h b/esp32/LedController.h index ee00234..0ee4181 100644 --- a/esp32/LedController.h +++ b/esp32/LedController.h @@ -1,4 +1,5 @@ #include "alarm.h" +#include "Arduino.h" class LedController { private: @@ -22,7 +23,7 @@ public: static const int LED_OFF_VAL = 0; static const int LED_ON_VAL = 255; - LedController(AlarmStatus* statusObj){ + LedController(AlarmStatus* statusObj){ Serial.println("const."); status = statusObj; } @@ -31,6 +32,7 @@ public: redPin = redLedPin; greenPin = greenLedPin; } + void Init(){ pinMode(bluePin, OUTPUT); pinMode(redPin, OUTPUT); @@ -66,7 +68,16 @@ public: turnOff(redPin); turnOff(greenPin); } - + void Cyan(){ + turnOn(bluePin); + turnOn(greenPin); + turnOff(redPin); + } + void Magenta(){ + turnOn(bluePin); + turnOff(greenPin); + turnOn(redPin); + } void Error(){ Red(); delay(100); diff --git a/esp32/ServerConnector.h b/esp32/ServerConnector.h new file mode 100644 index 0000000..9d62949 --- /dev/null +++ b/esp32/ServerConnector.h @@ -0,0 +1,156 @@ +#include "alarm.h" +#include "Times.h" +#include +// #include +// #include +#include +#include + +class ServerConnector { +private: + AlarmStatus* status; + long lastUpdate; + WiFiClient* wifiClient; + CardReader* _cardReader; + + const String AUTHORIZED_ENTRANCE = "AUTHORIZE_ENTRANCE"; + const String ServerAddress = "10.88.88.169:9003"; + const String EVEN_TYPE_FIRED = "Fired"; + const String EVENT_TYPE_EVENT_UPDATE = "EventUpdate"; + const String EVENT_TYPE_UPDATE = "Update"; + + const String FIELD_DISARM = "disarm"; + const String FIELD_ALLOWED_CARDS = "cards"; + + void HandTask() { + // ServerConnector * this = (ServerConnector *) pvParameters; + for (;;) { + //every 1 minutes ask for update: DISSARM & CARDS + if (lastUpdate + FromSeconds(15) < millis()) { + lastUpdate = millis(); + RequestUpdate(); + } + + if (!status->sendNotif && !status->isFired) { + vTaskDelay(100 / portTICK_PERIOD_MS); + continue; + } + if (status->sendNotif) { + status->eventId = millis(); + } + SendAlarm(); + status->sendNotif = false; + vTaskDelay(FromSeconds(3) / portTICK_PERIOD_MS); + } + } + + void SendAlarm() { + String eventtype = status->sendNotif ? EVEN_TYPE_FIRED : EVENT_TYPE_EVENT_UPDATE; + String url = "http://" + ServerAddress + "/?eventId=" + String(status->eventId) + "&eventType=" + eventtype + "&eventData=t"; + String response = MakeHttpCall(url); + if(response == ""){ + Serial.println("Alarm Server not recheable"); + return; + } + + if (response == AUTHORIZED_ENTRANCE) { + //Todo Extract to Disarm method + Serial.println("[HTTP] Entrace authorized by server."); + status->isFired = false; + status->isArmed = status->doorStatus == DOOR_CLOSED; + } + } + + void RequestUpdate() { + String url = "http://" + ServerAddress + "/?eventId=0&eventType=" + EVENT_TYPE_UPDATE + "&eventData=t"; + String response = MakeHttpCall(url); + if(response == ""){ + Serial.println("Update Server not recheable"); + return; + } + + Dictionary& d = *(new Dictionary()); + JsonDocument doc; + // deserializeJson(doc, response); + + DeserializationError error = deserializeJson(doc, response); + + + if (error) { + Serial.print("Serialize error: "); + Serial.println(error.c_str()); + return; + } + + + if(doc[FIELD_DISARM].is() && doc[FIELD_DISARM] ){ + Serial.println("Disarm request by server"); + status->isArmed=false; + status->isFired=false; + } + + // Serial.print(FIELD_ALLOWED_CARDS); + int cardsNo = doc[FIELD_ALLOWED_CARDS].size(); + + for(int i=0; i < cardsNo ; i++){ + _cardReader->AddUser(doc[FIELD_ALLOWED_CARDS][i]["id"], doc[FIELD_ALLOWED_CARDS][i]["name"]); + } + + } + + String MakeHttpCall(String url) { + if (!wifiClient) { + Serial.printf("[HTTPS] Unable to connect\n"); + return ""; + } + + HTTPClient https; + + + Serial.println("[HTTPS] " + url); + + if (!https.begin(*wifiClient, url)) { // HTTPS + Serial.println("not able to start http call"); + return ""; + } + // Serial.print("[HTTPS] GET...\n"); + // start connection and send HTTP header + int httpCode = https.GET(); + // httpCode will be negative on error + + if (httpCode <= 0) { + Serial.printf("[HTTP] GET... failed, error: %s\n", https.errorToString(httpCode).c_str()); + return ""; + } + + // HTTP header has been send and Server response header has been handled + // Serial.printf("[HTTPS] GET Finished... code: %d\n", httpCode); + // file found at server + if (httpCode != HTTP_CODE_OK) { + https.end(); + return ""; + } + + + // print server response payload + String payload = https.getString(); + https.end(); + return payload; + } +public: + + ServerConnector(AlarmStatus* statusObj, CardReader* cardReader) { + status = statusObj; + wifiClient = new WiFiClient(); + _cardReader = cardReader; + } + + void StartNotifierAsync() { + xTaskCreate(this->asynTask, "sendNotif", 6000, (void*)this, 2, NULL); + } + + static void asynTask(void* pvParameter) { + ServerConnector* serverInstance = (ServerConnector*)pvParameter; + serverInstance->HandTask(); + } +}; diff --git a/esp32/Times.h b/esp32/Times.h new file mode 100644 index 0000000..8647f4b --- /dev/null +++ b/esp32/Times.h @@ -0,0 +1,16 @@ +#ifndef _TIMES_H_ +#define _TIMES_H_ + +long FromMinutes(long min){ + return min * 60000; +} + +long FromSeconds(long sec){ + return sec * 1000; +} + +long FromHours(long hs){ + return hs * 3600000; +} + +#endif diff --git a/esp32/alarm.h b/esp32/alarm.h index 14178d2..6c7e0f5 100644 --- a/esp32/alarm.h +++ b/esp32/alarm.h @@ -11,6 +11,12 @@ struct AlarmStatus{ bool ledOn =true; bool muted =false; bool silent =false; //low sound + bool showError=false; + bool allowed=false; + long lastEntrance=0; + String userAllowed; + bool sendNotif=false; + long eventId=0; }; #endif diff --git a/esp32/doorSensor.h b/esp32/doorSensor.h index c1495e7..f02cf12 100644 --- a/esp32/doorSensor.h +++ b/esp32/doorSensor.h @@ -4,13 +4,13 @@ AlarmStatus* status; class DoorSensor { private: - int DOOR_SENSOR_PIN = 23; + int DOOR_SENSOR_PIN = 14; AlarmStatus* status; int lastDoorState=1; public: - static const int DEFAULT_DOOR_SENSOR_PIN=23; + static const int DEFAULT_DOOR_SENSOR_PIN=14; DoorSensor(AlarmStatus* statusObj, int doorSensorPin){ DOOR_SENSOR_PIN = doorSensorPin; diff --git a/esp32/esp32.ino b/esp32/esp32.ino index 36e21b7..538787f 100644 --- a/esp32/esp32.ino +++ b/esp32/esp32.ino @@ -1,14 +1,31 @@ #include +// #include "DictionaryDeclarations.h" +#include #include "alarm.h" #include "DoorSensor.h" #include "LedController.h" #include "Siren.h" -// #include +#include "CardReader.h" +#include "soc/rtc_wdt.h" +#include +#include "ServerConnector.h" +// #include +// #include "FrancelsoftCert.h" + +#include "Times.h" +// #include AlarmStatus s; DoorSensor doorSensor(&s); LedController led(&s); Siren siren(&s); +CardReader cardReader(&s); +ServerConnector serverConnector(&s, &cardReader); + +const int SILENCE_JMP_PIN = 12; +//const char* server = "push.francelsoft.com"; // Server URL + + void printStatus() { @@ -28,32 +45,66 @@ void setup() doorSensor.Init(); led.Init(); siren.Init(); + cardReader.Init(); - s.silent = true; + pinMode(SILENCE_JMP_PIN, INPUT_PULLUP); + + s.silent = false; s.isArmed = doorSensor.IsDoorClosed(); + addUsers(); + // WiFi.mode(WIFI_STA); // WiFi.disconnect(); // delay(100); + SoundAlarmAsync(); + // StartNotifierAsync(); printStatus(); + + ConnectToWifi(); + + // setClock(); + serverConnector.StartNotifierAsync(); +} + +void addUsers(){ + cardReader.AddUser("0438768a2c6a80", "pin verizure"); + // cardReader.AddUser("23141f2d", "pin azul"); + cardReader.AddUser("91cf3e02", "card access"); } void loop() { + //Inputs + s.silent = digitalRead(SILENCE_JMP_PIN) == HIGH; + doorSensor.HandleDoor(); + if(cardReader.IsInit()){ + cardReader.HandleCard(); + }else{ + cardReader.Init(); + } + + if(s.allowed){ + HandleUserPresent(); + s.allowed=false; + } + if (s.doorChanged) { DoorEvent(); - } - s.doorChanged = false; - - if (s.isFired) - { - siren.SoundSiren(); + s.doorChanged = false; } + AutoRearm(); + + //Output + if(s.showError){ + led.Error(); + s.showError=false; + } led.Update(); // delay(1000); @@ -64,13 +115,18 @@ void DoorEvent() if (doorSensor.IsDoorOpen()) { Serial.println("The door-opening"); + if (!s.isArmed) { Serial.println("Alarm is dissarmed, not fireing"); return; } + if(s.isFired){ // Already fired. + return; + } Serial.println("Alarm is armed, firing"); s.isFired = true; + s.sendNotif=true; } else { @@ -79,3 +135,91 @@ void DoorEvent() s.isArmed = true; } } + +void HandleUserPresent(){ + Serial.print("User Allowed: "); + Serial.println(s.userAllowed); + s.lastEntrance=millis(); + if(s.isFired){ + s.isFired=false; + s.isArmed=s.doorStatus==DOOR_CLOSED; + }else{ + s.isArmed=false; + } +} + +void AutoRearm(){ + if(s.isArmed){ + return; + } + if(s.lastEntrance + FromMinutes(3) < millis()){ + + //Auto Rearm if door is closed. + if(s.doorStatus == DOOR_CLOSED){ + Serial.println("5m Passed, AutoArming again"); + s.isArmed= true; + } + + //Autofire if door open when expired + // if(s.doorStatus == DOOR_OPEN){ + // s.isFired=true; + // return; + // } + } +} + +TaskHandle_t SoundTask; +void SoundAlarmAsync(){ + xTaskCreate(SoundAlarmIntAsync, "task1", 1000, NULL, 1, NULL); +} + +void SoundAlarmIntAsync( void * pvParameters ){ + for(;;){ + if (!s.isFired) + { + vTaskDelay( 200 / portTICK_PERIOD_MS ); + continue; + } + siren.SoundSiren(); + vTaskDelay( 1 / portTICK_PERIOD_MS ); + } +} + + +void ConnectToWifi(){ + // We start by connecting to a WiFi network + WiFi.begin("Guile&Andre", "popolitoproducciones"); + + Serial.println(); + Serial.println(); + Serial.print("Waiting for WiFi... "); + + while(WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); +} + + +void setClock() { + // configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov"); + configTime(0, 0, "pool.ntp.org", "time.nist.gov"); + + Serial.print("Waiting for NTP time sync: "); + time_t now = time(nullptr); + while (now < 8 * 3600 * 2) { + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print("Current time: "); + Serial.print(asctime(&timeinfo)); +} \ No newline at end of file