ESP32 Code
/*
* ESP32 Webserver für den Datenaustausch zwischen ESP32 <--> Fibaro-HC3
* RFID Leser ansprechenn und Code zum QA HC3 senden.
* Bei Übereinstimmung Relais schalten
* Datenverkehr in einem Json-String versenden.
* Jegliche Daten werden Verschlüsselt übertragen. HC3 <-> ESP32
*
* Anzeige der Übermittelten und endfangenen Daten mittels OLED-128x64-i2c
*
* Die erfolgreiche Datenübermittlung zum HC3 wird mit dem Wechel
* der 2 LED´2 out_1 und out_2 angezeigt.
*
* Angegeben werden müßen für den Router
* ssid = "Geheim"
* password = "Super Geheim"
*
* ESP32_RFID_Garage_V1.0
* Erstellt am 06.04.2021
* Frank Berges
* ---------------------------------
* Enderungsindex
* V1.0 06.04.2021 F.B.
* V2.0 16.04.2021 F.B.
* Datenverkehr verschluesselt HC3 <-> ESP
* Auswertung findet jetzt im ESP32 stat und nicht mehr im HC3
* Die Daten für den RFID-Vergleich werden vom HC3 übermittelt
* und im Flash abgespeichert, somit stehen diese nach jebem
* Neuen Einschalten sofort zurverfügung und müssen nicht
* neu Übermittelt werden. Ein Übermittlungsbefehl wird vom
* QA aus über einen Button angestossen.
*
* =============================================================================
*/
// Load librarys
//-----------------------------------------------------------------------------
#include <deprecated.h>
#include <require_cpp11.h>
#include "time.h" // Zeitdarstellungen
#include <ssl_client.h>
#include <string>
#include <iostream>
#include <WiFi.h>
#include <Wire.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <MFRC522.h>
#include <MFRC522Extended.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h> // für Display
#include <Adafruit_Sensor.h>
#include <Preferences.h> // Variabel im Flash ablegen
#include <WiFiClientSecure.h>
extern "C"
{
#include "crypto/base64.h"
}
//-----------------------------------------------------------------------------
// Vorbereitung des SSD1306 display I2C
//-----------------------------------------------------------------------------
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
//-----------------------------------------------------------------------------
// Vorbereitung des Timeserver zugriffs
//-----------------------------------------------------------------------------
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600;
const int daylightOffset_sec = 3600;
//-----------------------------------------------------------------------------
// Vorbereitung der Ausgänge
//-----------------------------------------------------------------------------
// Variabeln für die Ausgänge
#define ausgang_1 25 // wird von HC3 gesteuert
#define ausgang_2 26 // wird von HC3 gesteuert
#define Beep_PIN 2 // LED-blau-Pin
#define RST_PIN 33 // SPI-Pin RST-Pin
#define SDA_PIN 32 // SPI-Pin SS- bzw. SDA-Pin
//-----------------------------------------------------------------------------
//Web Daten für den Router
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char* ssid = "Geheim";
const char* password = "Super Geheim";
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//Sendedaten an HC3
//-----------------------------------------------------------------------------
String Software_Version = "ESP32_RFID_Garage_V2.0"; // Softwareversion
int age = 0;
String Daten_1 = ""; // Erster Kartendatensatz z.B "Karin Berges"
String Daten_2 = ""; // Zweiter Kartendatensatz z.B "B2 3E 7C 31"
String sende_json = ""; // Sendedaten an den HC3
//-----------------------------------------------------------------------------
//RFID-Daten
//-----------------------------------------------------------------------------
struct astruct
{
String RFID_Name;
String RFID_Code;
};
struct astruct RFID_Daten[50]; //Maximal 50 RFID-Tag´s sind vorgesehen
//Möglicher zugriff ist : RFID_Daten[3].RFID_Name = "Frank";
String Rohdaten = ""; // Für die Datenübergabe
Preferences preferences; //Abspeichern der Daten
//-----------------------------------------------------------------------------
//Gegentacktblinker
//-----------------------------------------------------------------------------
byte out_1 = 0;
byte out_2 = 0;
//-----------------------------------------------------------------------------
//Lese und Auswertebestätigung
//-----------------------------------------------------------------------------
bool RFID_gelesen = false;
//-----------------------------------------------------------------------------
//Für die Displayanzeige Systemzeit
//-----------------------------------------------------------------------------
long myTimer = 0;
long myTimeout = 1000; //Blinkzeit ein & aus
//-----------------------------------------------------------------------------
//Webserver vorbereiten
//-----------------------------------------------------------------------------
// Set web server port number to 80
WiFiServer server(80);
// Variable to store the HTTP request
String header; // Transferdaten von http
String input; // im header endhaltene Daten als json
//-----------------------------------------------------------------------------
//MFRC522-Instanz erstellen
//-----------------------------------------------------------------------------
MFRC522 mfrc522(SDA_PIN, RST_PIN);
//-----------------------------------------------------------------------------
// Timeout definieren
//-----------------------------------------------------------------------------
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
//-----------------------------------------------------------------------------
//*********************************** SETUP ***********************************
//-----------------------------------------------------------------------------
void setup()
{
//SSD1306 display I2C
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
{
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(2000);
display.clearDisplay();
display.setTextColor(WHITE);
//Zeit von Zeitserver holen
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED für Timeserver");
//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
//ACHTUNG
//Erst mit der ersten Ausgabe wird die Zeit übertragen zum Internen Timer
printLocalTime();
//disconnect WiFi
WiFi.disconnect(true);
// Bestimmen der pin-Funktion
pinMode(ausgang_1, OUTPUT);
pinMode(ausgang_2, OUTPUT);
pinMode(Beep_PIN, OUTPUT); //Beeper
digitalWrite(Beep_PIN, LOW); //RC522
//SPI-Bus Initialisieren
SPI.begin();
//RFID-RC522 initialisieren
mfrc522.PCD_Init();
Serial.begin(115200);
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to Network:");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
// Print the connnect IP address and start web server
Serial.println("");
Serial.println("Connected. The device can be found at IP address: ");
Serial.println(WiFi.localIP());
server.begin();
//Daten aus dem Flash holen
Rohdaten = Daten_aus_dem_Flash("Flash_RFID");
//Json-String in Variabel überführen
json_string_in_Variabel();
}
//-----------------------------------------------------------------------------
//******************************* Hauptprogramm *******************************
//-----------------------------------------------------------------------------
void loop()
{
WiFiClient client = server.available(); // Listen for incoming clients
if (client)
{ // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client found."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime)
{ // loop while the client's connected
currentTime = millis();
if (client.available())
{ // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n')
{ // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0)
{
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: data/json");
client.println("Connection: close");
client.println();
client.println();
// Anzeige der Werte im Display
display_anzeigen();
// send sensor data in JSON format
uebergabestring(); //Zusammenbauen des json Strings
//Sendedaten verschlüsseln
sende_json = encodeBase64 (sende_json);
client.println(sende_json); //Senden des Strings
Daten_1 = "";
Daten_2 = "";
// Break out of the while loop
break;
}
else
{ // if you got a newline, then clear currentLine
currentLine = "";
}
}
else if (c != '\r')
{ // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Daten im Hader verarbeiten
reaktionaufanfrage(header);
//Header Löschen
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
// Einholen der RFID
RFID_lesen();
RFID_vergleichen();
if (RFID_gelesen)
{
if (Daten_1 != "Unbekannt")
{
// REFID bekannt
digitalWrite(Beep_PIN, HIGH);
delay(50); //50ms
digitalWrite(Beep_PIN, LOW);
}
else
{
//RFID unbekannt
digitalWrite(Beep_PIN, HIGH);
delay(600); //600ms
digitalWrite(Beep_PIN, LOW);
}
RFID_gelesen = false;
}
//Ausgabe der Systemzeit
display_systemzeit();
} // End Loop
//-----------------------------------------------------------------------------
//------------------------------ RFID Auslesen --------------------------------
//-----------------------------------------------------------------------------
void RFID_lesen()
{
if (Daten_2 == "") //Die letzen Daten wurden übermittelt?
{
String rfidTag= "";
if (mfrc522.PICC_IsNewCardPresent() && // liegt ein neues Tag vor
mfrc522.PICC_ReadCardSerial())
{ // richtige Tag-Art
Serial.print("RFID-Tag/Karten-ID:");
for (byte i = 0; i < mfrc522.uid.size; i++)
{ // Karten-ID extrah.
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
rfidTag.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
rfidTag.concat(String(mfrc522.uid.uidByte[i], HEX));
}
Serial.println();
Daten_1 = "";
Daten_2 = rfidTag.substring(1);
RFID_gelesen = true;
}
}
}
//-----------------------------------------------------------------------------
//---------------------- RFID mit Vorgaben vergleichen ------------------------
//-----------------------------------------------------------------------------
void RFID_vergleichen()
{
if (RFID_gelesen)
{
for (int i=0; i < 50; i++)
{
if (RFID_Daten[i].RFID_Code == Daten_2)
{
//Daten dem Nahmen zuordnen
Daten_1 = RFID_Daten[i].RFID_Name;
display_infozeile("RFID Daten gefunden");
break;
}
else
{
Daten_1 = "Unbekannt";
}
}
}
}
//-----------------------------------------------------------------------------
//--------- Aus dem Inputstring die Json Daten holen und verarbeiten ----------
//-----------------------------------------------------------------------------
String reaktionaufanfrage(String Eingangswert)
{
// Raussuchen was an Daten gesendet wurde
Rohdaten = Eingangswert.substring (Eingangswert.indexOf("data:")+5, Eingangswert.indexOf("Content"));
//Jetzt müssen die Daten noch decodiert werden
Rohdaten = decodeBase64(Rohdaten);
if (Eingangswert.indexOf("data/json") > -1) //Kommen Reaktionsdaten ? -1 = nein
{
Serial.println("Daten kommen");
StaticJsonDocument<128> doc;
DeserializationError error = deserializeJson(doc, Rohdaten);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
}
else // Alles OK
{
//Sendestring inhalt auf Variabeln übertragen
const char* s_time = doc["time"]; // "05:22:00" hh:mm:ss
out_1 = doc["out_1"]; //0 oder 1
out_2 = doc["out_2"]; //0 oder 1
// Schalten der Ausgänge
if (out_1 == 1)
{
//Serial.println("GPIO 25 on");
out_1 = 1;
digitalWrite(ausgang_1, HIGH);
}
if (out_1 == 0)
{
//Serial.println("GPIO 25 off");
out_1 = 0;
digitalWrite(ausgang_1, LOW);
}
if (out_2 == 1)
{
//Serial.println("GPIO 26 on");
out_2 = 1;
digitalWrite(ausgang_2, HIGH);
}
if (out_2 == 0)
{
//Serial.println("GPIO 26 off");
out_2 = 0;
digitalWrite(ausgang_2, LOW);
}
}
}
if (Eingangswert.indexOf("memo/json") > -1) //Kommen Speicherdaten ? -1 = nein
{
Serial.println("Memos kommen");
display_infozeile("Neue Daten vom HC3");
//Json-String <Rohdaten> in Variabel überführen
json_string_in_Variabel();
//Daten im Flash Abspeichern
Daten_im_Flash_speichern("Flash_RFID", Rohdaten);
}
//In der Globalen Variabel abspeichern
input = Eingangswert;
}
//-----------------------------------------------------------------------------
//--------------- Json-String zusammen bauen für das versenden ----------------
//-----------------------------------------------------------------------------
void uebergabestring()
{
// Hier wird das JSON-Objekt erstellt
DynamicJsonDocument configJSON(1024);
configJSON["software_version"] = Software_Version;
configJSON["age"] = 0;
configJSON["out_1"] = out_1;
configJSON["out_2"] = out_2;
configJSON["sensordatavalues"][0]["value_type"] = "Daten_1";
configJSON["sensordatavalues"][0]["value"] = Daten_1;
configJSON["sensordatavalues"][1]["value_type"] = "Daten_2";
configJSON["sensordatavalues"][1]["value"] = Daten_2;
configJSON["sensordatavalues"][2]["value_type"] = "signal";
configJSON["sensordatavalues"][2]["value"] = WiFi.RSSI();
sende_json = "";
serializeJson(configJSON, sende_json);
//Serial.println(sende_json);
}
//-----------------------------------------------------------------------------
//--------------- Json-String zusammen bauen für das versenden ----------------
//-----------------------------------------------------------------------------
void json_string_in_Variabel()
{
StaticJsonDocument<1024> doc; //Das solte für einige RFID-Tags reichen
DeserializationError error = deserializeJson(doc, Rohdaten);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
}
else
{
const char* time = doc["time"]; // "13:30:22"
int count = 0;
for (JsonObject elem : doc["Codedaten"].as<JsonArray>())
{
///Daten vom HC3 in einer Structur hinterlegen
const char* RFID_Name = elem["RFID_Name"]; // "Karin", "Frank" usw.
const char* RFID_Code = elem["RFID_Code"]; // "B2 3E 7C 31", "6c 3d 41 33" usw.
RFID_Daten[count].RFID_Name = RFID_Name;
RFID_Daten[count].RFID_Code = RFID_Code;
if (count < 50) // ACHTUNG Max 50 Stück
{
count = count + 1;
}
}
}
// Jetzt sind die Daten aus dem json in der Struktur.
Rohdaten = ""; //Wieder leeren
}
//-----------------------------------------------------------------------------
//--------------------------- BASE64 encode/decode ----------------------------
//-----------------------------------------------------------------------------
String encodeBase64 (String Input_Text)
{
String Output_Code;
char* toEncode = strstr( Input_Text.c_str(), "\0" ); //Neue Version
//char* toEncode = (char*) Input_Text.c_str(); //Alte Version
size_t outputLength;
unsigned char * encoded = base64_encode((const unsigned char *)toEncode, strlen(toEncode), &outputLength);
Output_Code = (const char*)encoded;
Output_Code = Output_Code.substring(0,outputLength);
free(encoded);
return Output_Code;
}
//.........................................................
String decodeBase64 (String Input_Code)
{
String Output_Text;
char* toDecode = strstr( Input_Code.c_str(), "\0" ); //Neue Version
//char* toDecode = (char*) Input_Code.c_str(); //Alte Version
size_t outputLength;
unsigned char * decoded = base64_decode((const unsigned char *)toDecode, strlen(toDecode), &outputLength);
Output_Text = (const char*)decoded;
Output_Text = Output_Text.substring(0,outputLength);
free(decoded);
return Output_Text;
}
//-----------------------------------------------------------------------------
//------------------------ Daten im Flash hinterlegen -------------------------
//https://github.com/espressif/arduino-esp32/tree/master/libraries/Preferences
//-----------------------------------------------------------------------------
void Daten_im_Flash_speichern(const char * Save_Variabel, String Save_Data)
{
// Öffenen der Preferences
// RW-mode (Zweiter parameter muss auf false stehen).
// Note: Nameslänge des Platzhalters max. 15 Zeichen.
preferences.begin(Save_Variabel, false);
// Lösche alle Save_Platzhalten
//preferences.clear();
//Löschen nur eines Platzhalters
preferences.remove(Save_Variabel);
// Abspeichern der Daten auf den Platzhalter
preferences.putString(Save_Variabel, Save_Data);
// Schließen der Preferences
preferences.end();
}
//-----------------------------------------------------------------------------
//------------------------ Daten aus dem Flash hohlen -------------------------
// https://github.com/espressif/arduino-esp32/tree/master/libraries/Preferences
//-----------------------------------------------------------------------------
String Daten_aus_dem_Flash(const char * Save_Variabel)
{
// Öffenen der Preferences
// RW-mode (Zweiter parameter muss auf false stehen).
// Note: Nameslänge des Platzhalters max. 15 Zeichen.
preferences.begin(Save_Variabel, false);
// Einholen eines Srings aus dem Flash Platzhalter 1 Variabel
// Wenn der Platzhalter nicht da ist kommt ein 0 zurück
// Note: Nameslänge des Platzhalters max. 15 Zeichen.
String Flash_Daten = preferences.getString(Save_Variabel,"");
// Schließen der Preferences
preferences.end();
return Flash_Daten;
}
//-----------------------------------------------------------------------------
//---------------------------- Ausgabe Systemzeit -----------------------------
//-----------------------------------------------------------------------------
void printLocalTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}
//-----------------------------------------------------------------------------
//-------------------- Ausgabe der Daten auf dem SSD1306 ----------------------
//-----------------------------------------------------------------------------
void display_anzeigen()
{
// clear display
display.clearDisplay();
// Alles was ausgegeben wird in der Schriftgroesse
display.setTextSize(1);
//display Datensatz RFID 1
display.setCursor(0,0);
display.print("Daten_1 : ");
display.print(Daten_1);
//display Datensatz RFID 2
display.setCursor(0,10);
display.print("Daten_2 : ");
display.print(Daten_2);
//display Zeile 3
//display.setCursor(0,20);
//display.print("xxxxx : ");
//display.print(Variabel);
//display.print(" xx");
//display Zeile 4
//display.setCursor(0,30);
//display.print("xxxxxx : ");
//display.print(Variabel);
//display.print(" xx");
//display Ausgang 1
display.setCursor(0,40);
display.print("Out_1 : ");
display.print(out_1);
display.print(" / ");
//display Ausgang 2
display.print("Out_2 : ");
display.print(out_2);
display.print(" ");
display.drawLine(0,50,128,50,1); // Zeichnet eine Linie mit Hilfe von Start- und Endkoordinaten;
//display Systemzeit
display.setCursor(0,53);
display.print("Systemzeit : "); // An dieser Stelle wird die Systemzeit ausgegeben
display.drawLine(0,62,128,62,1); // Zeichnet eine Linie mit Hilfe von Start- und Endkoordinaten;
display.display(); // Alles aus dem Speicher zur Anzeige bringen
}
//-----------------------------------------------------------------------------
//Für die Anzeige der Systemzeit
//-----------------------------------------------------------------------------
void display_systemzeit()
{
if (millis() > myTimeout + myTimer )
{
myTimer = millis();
struct tm timeinfo;
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
}
else
{
//Die alte Anzeige löschen
display.drawFastHLine(80,53,50,SSD1306_BLACK);
display.drawFastHLine(80,54,50,SSD1306_BLACK);
display.drawFastHLine(80,55,50,SSD1306_BLACK);
display.drawFastHLine(80,56,50,SSD1306_BLACK);
display.drawFastHLine(80,57,50,SSD1306_BLACK);
display.drawFastHLine(80,58,50,SSD1306_BLACK);
display.drawFastHLine(80,59,50,SSD1306_BLACK);
display.drawFastHLine(80,60,50,SSD1306_BLACK);
//Zeit anzeigen
display.setTextSize(1);
display.setCursor(80,53);
display.print(&timeinfo, "%H:%M:%S");
display.display();
}
}
}
//-----------------------------------------------------------------------------
//Für die Anzeige der Infozeile max 22 Zeichen
//-----------------------------------------------------------------------------
void display_infozeile(String Text)
{
//Die alte Anzeige löschen
display.drawFastHLine(0,20,127,SSD1306_BLACK);
display.drawFastHLine(0,21,127,SSD1306_BLACK);
display.drawFastHLine(0,22,127,SSD1306_BLACK);
display.drawFastHLine(0,23,127,SSD1306_BLACK);
display.drawFastHLine(0,24,127,SSD1306_BLACK);
display.drawFastHLine(0,25,127,SSD1306_BLACK);
display.drawFastHLine(0,26,127,SSD1306_BLACK);
display.drawFastHLine(0,27,127,SSD1306_BLACK);
//Text auf 22 Zeichen begrenzen
Text = Text.substring (0, 22);
//int x= (128-(Text.length()*6))/2;
//Text anzeigen
display.setTextSize(1);
display.setCursor((128-(Text.length()*6))/2,20);
display.print(Text);
display.display();
}
//-----------------------------------------------------------------------------
// EOF
Ist jetzt kein Meisterwerk aber es funktioniert gut !
Grusse Frank und viel Spas beim basteln.
Hier was nachgeschoben !
Hier könnt Ihr sehen wie es funktioniert !
Chriss wahr so nett und hat es veröffendlicht.
RFID | SmartHome Blog - YouTube