This shows you the differences between two versions of the page.
iothings:proiecte:2021:homesecurity [2022/01/27 23:20] robert.olteanu1909 [Software Description] |
iothings:proiecte:2021:homesecurity [2022/01/28 01:14] (current) robert.olteanu1909 [References] |
||
---|---|---|---|
Line 19: | Line 19: | ||
* **LCD 16x2 with I2C Interface** -> A Liquid Crystal Display (LCD), which is a basic module and used commonly in various devices and circuits. 16x2 means it can display 16 characters per line and there are 2 lines. The Inter-Integrated Circuit (I2C) it's a bus interface connection protocol incorporated into devices for serial communication. | * **LCD 16x2 with I2C Interface** -> A Liquid Crystal Display (LCD), which is a basic module and used commonly in various devices and circuits. 16x2 means it can display 16 characters per line and there are 2 lines. The Inter-Integrated Circuit (I2C) it's a bus interface connection protocol incorporated into devices for serial communication. | ||
- | I attached below a diagram generated using [[https://www.circuito.io/|circuito.io]], but I used a version that involved less wires. | + | I attached below a diagram generated using [[https://www.circuito.io/|circuito.io]], **but I used a version that involved less wires**. |
{{ :iothings:proiecte:2021:hs_hschematic.png?nolink |}} | {{ :iothings:proiecte:2021:hs_hschematic.png?nolink |}} | ||
Line 37: | Line 37: | ||
Next thing the software is split in two main parts: | Next thing the software is split in two main parts: | ||
- Initial setup - this is where all the components / modules are getting initialized | - Initial setup - this is where all the components / modules are getting initialized | ||
- | * WiFi - The ESP32 tries to connect to the configured network until succeed and it gets the IP address | + | * **WiFi** - The ESP32 tries to connect to the configured network until succeed and it gets the IP address |
- | * MQTT - The Adafruit.io supports data transfer using MQTT, and on this initial setup there is needed to subscribe to all topics needed | + | * **MQTT** - The Adafruit.io supports data transfer using MQTT, and on this initial setup there is needed to subscribe to all topics needed while the publishers doesn't need to. |
- | * RFC522 - Initialize the SPI Bus then initialize the RFID module. | + | |
- | * | + | <code c> |
+ | #include "Adafruit_MQTT.h" | ||
+ | #include "Adafruit_MQTT_Client.h" | ||
+ | |||
+ | Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); | ||
+ | Adafruit_MQTT_Publish hs_log = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/HS_Log"); | ||
+ | Adafruit_MQTT_Publish hs_door = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/HS_DoorStatus"); | ||
+ | Adafruit_MQTT_Subscribe hs_code = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/HS_DoorCode"); | ||
+ | ... | ||
+ | mqtt.subscribe(&hs_code); | ||
+ | </code> | ||
+ | |||
+ | * **RFC522** - Initialize the SPI Bus then initialize the RFID module. | ||
+ | * **LCD16x2** - Initialize the LCD and if the module supports, the backlight for a better display of messages | ||
+ | * **Keypad** - Define the keypad and it's GPIO pins used | ||
+ | |||
+ | <code c> | ||
+ | #include <Keypad.h> | ||
+ | #include <SPI.h> | ||
+ | #include <MFRC522.h> | ||
+ | #include <LiquidCrystal_I2C.h> | ||
+ | |||
+ | // Keypad | ||
+ | #define ROW_NUM 4 | ||
+ | #define COLUMN_NUM 3 | ||
+ | char keys[ROW_NUM][COLUMN_NUM] = { | ||
+ | {'#', '0', '*'}, | ||
+ | {'9', '8', '7'}, | ||
+ | {'6', '5', '4'}, | ||
+ | {'3', '2', '1'} | ||
+ | }; | ||
+ | |||
+ | byte pin_rows[ROW_NUM] = {0, 2, 15, 13}; | ||
+ | byte pin_column[COLUMN_NUM] = {17, 16, 4}; | ||
+ | Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM ); | ||
+ | |||
+ | // MFRC522 | ||
+ | #define SS_PIN 5 // ESP32 pin GIOP5 | ||
+ | #define RST_PIN 27 // ESP32 pin GIOP27 | ||
+ | MFRC522 rfid(SS_PIN, RST_PIN); | ||
+ | |||
+ | // LCD | ||
+ | int lcdColumns = 16; | ||
+ | int lcdRows = 2; | ||
+ | LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows); | ||
+ | |||
+ | ... | ||
+ | |||
+ | SPI.begin(); // init SPI bus | ||
+ | rfid.PCD_Init(); // init MFRC522 | ||
+ | |||
+ | lcd.init(); | ||
+ | lcd.backlight(); | ||
+ | |||
+ | </code> | ||
- Loop - this is looping until the ESP32 is stopped by user. | - Loop - this is looping until the ESP32 is stopped by user. | ||
- | ====== Workflow ====== | + | * **Connect to MQTT** - this is done on each iteration to ensure a good connectivity |
- | {{ iothings:proiecte:2021:hs_schematic.png }} | + | * **Read code subscription** - first time after initial setup the user must insert his/her keycode of 4 characters inside Adafruit.io dashboard |
+ | <code c> | ||
+ | MQTT_connect(); | ||
+ | Adafruit_MQTT_Subscribe *subscription; | ||
- | ====== References ====== | + | // Await code to be set from dashboard |
+ | while(code.equals("####")){ | ||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0,0); | ||
+ | lcd.print("Awaiting code..."); | ||
+ | while((subscription = mqtt.readSubscription(5000))) { | ||
+ | if(subscription == &hs_code) { | ||
+ | Serial.print(F("Got: ")); | ||
+ | Serial.println((char*)hs_code.lastread); | ||
+ | code = (char*)hs_code.lastread; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | * **Card scan** - Wait until a card is scanned and check if it's a valid one | ||
+ | <code c> | ||
+ | if(rfid.PICC_IsNewCardPresent()) { | ||
+ | Serial.println("Card present"); | ||
+ | if(rfid.PICC_ReadCardSerial()) { | ||
+ | Serial.println("Read Serial"); | ||
+ | for (int i=0; i<rfid.uid.size; i++) { | ||
+ | if(rfid.uid.uidByte[i] != availableCard[i]) { | ||
+ | char msg[] = "Invalid card scanned"; | ||
+ | hs_log.publish(msg); // publish message | ||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0,0); | ||
+ | lcd.print("Invalid card"); | ||
+ | delay(3000); // wait to be able to see the message from lcd | ||
+ | </code> | ||
+ | |||
+ | * **Type code** - If the card was valid the user is prompted to input the security code | ||
+ | |||
+ | <code c> | ||
+ | bool scannedCard() { | ||
+ | int idx = 0; | ||
+ | |||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0,0); | ||
+ | lcd.print("Insert code:"); | ||
+ | lcd.setCursor(0,1); | ||
+ | | ||
+ | do { | ||
+ | do{ | ||
+ | keyp = keypad.getKey(); | ||
+ | }while(!keyp); | ||
+ | kcode[idx] = keyp; | ||
+ | idx++; | ||
+ | lcd.print("*"); | ||
+ | }while(idx < 4); | ||
+ | |||
+ | for(int i=0; i<4;i++){ | ||
+ | if(kcode[i] != code.charAt(i)) { // code is the variable containing the current keycode | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | return true; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | * **Update status** - anything from opening a door / disabling alarm etc. | ||
+ | |||
+ | <code c> | ||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0,0); | ||
+ | lcd.print("Door opened"); | ||
+ | char msg[] = "Door opened"; | ||
+ | hs_log.publish(msg); // publish message to logs | ||
+ | delay(7000); // open door / disable alarm etc. | ||
+ | lcd.clear(); | ||
+ | lcd.setCursor(0,0); | ||
+ | lcd.print("Door closed"); | ||
+ | char msg2[] = "Door closed"; | ||
+ | hs_log.publish(msg2); // publish message to logs | ||
+ | delay(3000); // wait to be able to read the lcd message | ||
+ | </code> | ||
+ | ====== Software logical workflow ====== | ||
+ | Down below I created a small logical workflow for the code described in the previous chapter to be easily understood. | ||
+ | |||
+ | |||
+ | |||
+ | {{ iothings:proiecte:2021:hs_schematic.png }} | ||
+ | |||
+ | |||
+ | ====== References ====== | ||
+ | [1] - [[http://esp32.net/]] \\ | ||
+ | [2] - [[https://lastminuteengineers.com/how-rfid-works-rc522-arduino-tutorial/]] \\ | ||
+ | [3] - [[https://esp32io.com/tutorials/esp32-rfid-nfc]] \\ | ||
+ | [4] - [[https://randomnerdtutorials.com/esp32-esp8266-i2c-lcd-arduino-ide/]] \\ | ||
+ | [5] - [[https://esp32io.com/tutorials/esp32-keypad]] \\ | ||
+ | [6] - [[https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api]] \\ | ||
+ | [7] - [[https://raw.githubusercontent.com/AchimPieters/esp32-homekit-camera/master/Images/ESP32-38%20PIN-DEVBOARD.png]] \\ |