
# ESP Fingerprint (r503) for FHEM

[ESPHome](https://esphome.io/components/fingerprint_grow.html) based firmware for ESP32 or ESP8266 to manage and use a R503-RGB Fingerprint Reader over MQTT.

Supported features of my code:

* Control R503 LED
    * LED colors: RED, BLUE, PURPLE, GREEN, YELLOW, CYAN and WHITE
    * LED effects: BREATHING, FLASHING, ALWAYS_ON, ALWAYS_OFF, GRADUAL_ON and GRADUAL_OFF
* enroll a fingerprint to the reader
* delete fingerprint
* tutorial for fhem usage


<img src="doc/r503.gif" width="300">


# Getting started

## Config pins and effects

Set correct GPIO Pins in `fingerprintdoor.yaml`

```yaml
# -----------------------------
  # Config
  # -----------------------------
  devicename:           fingerprintdoor
  reader_rx_pin:        GPIO16
  reader_tx_pin:        GPIO17
  reader_sensor_pin:    GPIO5
  speed_flash:          "100"
  count_flash:          "4"
  speed_breath:         "75"
  count_breath:         "7"
  speed_gradual_off:    "200"
  speed_gradual_on:     "35"
```

## Wifi and MQTT
Create a `secrets.yaml`file in your project folder

```yaml
wifi_ssid: "YourSSID"
wifi_password: "YourPASS"
ota_password: "OtaPass"
mqtt_ip: "192.168.1.1"
mqtt_user: ""
mqtt_password: ""
```
## Flash to ESP
Follow this [GUIDE](https://esphome.io/guides/installing_esphome.html) to install ESPHome and flash it to your device with:

```shell
esphome run fingerprintdoor.yaml --device COM4
```
> Note: COM Port may differ, change it to your COM port
## FHEM MQTT2 device

```shell
defmod myFingerprintReader MQTT2_DEVICE fingerprintdoor
attr myFingerprintReader comment ToDo neuer Finger:\
- enroll neue ID\
- ID in userreading speichern\
- ID in Hashtable im notify eintragen (Admin oder Standard User)
attr myFingerprintReader event-on-change-reading .*
attr myFingerprintReader event-on-update-reading msg
attr myFingerprintReader setList GREEN:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
BLUE:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
RED:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
PURPLE:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
WHITE:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
CYAN:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
YELLOW:ALWAYS_ON,ALWAYS_OFF,BREATHING,FLASHING,GRADUAL_ON,GRADUAL_OFF fingerprintdoor/led/command {"color":"$EVTPART0","effect":"$EVTPART1","speed":150, "count":0}\
purple_breath fingerprintdoor/led/command {"color":"purple","effect":"breathing","speed":90, "count":0}\
light_master:noArg fingerprintdoor/led/command {"color":"BLUE","effect":"BREATHING","speed":165, "count":0}\
light_master_off:noArg fingerprintdoor/led/command {"color":"BLUE","effect":"GRADUAL_OFF","speed":165, "count":0}\
ready4finger:noArg fingerprintdoor/led/command {"color":"PURPLE","effect":"BREATHING","speed":165, "count":0}\
ready4finger_off:noArg fingerprintdoor/led/command {"color":"PURPLE","effect":"ALWAYS_OFF","speed":165, "count":0}\
custom fingerprintdoor/led/command {"color":"$EVTPART1","effect":"$EVTPART2","speed":$EVTPART3, "count":$EVTPART4}\
off:noArg fingerprintdoor/led/command {"color":"RED","effect":"ALWAYS_OFF","speed":20, "count":0}\
cancel:noArg fingerprintdoor/cancel_enroll\
enroll fingerprintdoor/enroll $EVTPART1\
delete fingerprintdoor/delete $EVTPART1\
\

attr myFingerprintReader userReadings ID1 {"Person 1"},\
ID2	{"Person 2"},\
ID3	{"Person 3"}
```

## Usage in FHEM

### Enroll new finger

Syntax:
```shell
set <fhem device name> enroll <finger ID>
```

Example:
```shell
set myFingerprint enroll 1
```

>Note: Enrollment cancel ist possible with:
```shell
set myFingerprint cancel
```

### Delete finger

Syntax:
```shell
set <fhem device name> delete <finger ID>
```

Example:
```shell
set myFingerprint delete 1
```

### Set Led color and effect
Syntax:
```shell
set <fhem device name> <color> <effect> <speed> <count>
```

Example:
```shell
set myFingerprint blue flash 120 3
```

>Note: If `<count>=0` for effect "flashing" or "breathing" will run continously and can be interrupted

# Example
I use a UserReading for my ID and finger management:

```
# [ID] [Rolle]: [Name-Finger]
# Gültige Rollen: Admin, Bewohner, Gast
ID11  {"Gast: Gastbenutzer Daumen links"},
ID12  {"Admin: Hausherr Daumen rechts"},
ID13  {"Bewohner: Leo Zeigefinger rechts"},
ID15  {"Gast: Oma Zeigefinger rechts"},
ID16  {"Admin: Opa Zeigefinger rechts"},
ID17  {"Gast: Opa Daumen rechts"},
ID18  {"Bewohner: Krissi Daumen rechts"}

```
If you define that, every ID and User has it's own Reading in FHEM:

<img src="doc/ur.png" width="300">


My whole access handling is defined in a notify. If the reader reports a finger ID the notify looks into the userReading for known fingers.

I also use 2 dummys. The first one is a master switch to disable the entire fingerprint access and the second one to allow guest access.

```
MQTT2_T_W_fingerprint:msg:.* {
if("$EVENT" =~ m/Authorized finger \d{1,3},.*/){
# Bekannte Finger in UserReading beim Reader definiert
  my $access = 0;
  my $maxConfidence = 100;
  my $finger_id = ReadingsVal("$NAME", "finger_id", 999);
  my $actual_confidence = ReadingsVal("$NAME", "confidence", 999);
  # Name und Finger aus Userreading holen
  my $finger_name = ReadingsVal("$NAME", "ID$finger_id", 999);

  # Nur in FHEM bekannte Finger zulassen, sonst return
  if($finger_name eq "999"){
	  Log3 "FingerprintDoor", 3, "ACHTUNG: Finger ID $finger_id ($finger_name) nicht in FHEM gespeichert!";
	  return;
  }
  
  
  # Finger funktionieren nur wenn Hauptschalter aktiv
  if(ReadingsVal("dmy_T_W_fingerprint_access", "state", "off") eq "on"){
	
  	### Admin Finger Actions
	if($finger_name =~ m/Admin: /){
	  Log3 "FingerprintDoor", 3, "Admin-Finger: $finger_id ($finger_name)";
	  if($actual_confidence < $maxConfidence){
		  Log3 "FingerprintDoor", 3, "Admin-Finger: Confidence ($actual_confidence) OK, grant access";
		  $access = 1;
	  }
	}elsif($finger_name =~ m/Bewohner: /){
	### Standard Finger
	  Log3 "FingerprintDoor", 3, "Standard-Finger: $finger_id ($finger_name)";
	  if($actual_confidence < $maxConfidence){
		  Log3 "FingerprintDoor", 3, "Standard-Finger: Confidence ($actual_confidence) OK, grant access";
		  $access = 1;
	  }
	}elsif($finger_name =~ m/Gast: /){
	# für bekannte Gäste bei Bedarf zum Aktivieren über dummy
		if($actual_confidence < $maxConfidence && ReadingsVal("dmy_fingerprint_guest_access", "state", "off") eq "on"){
		  Log3 "FingerprintDoor", 3, "Gast Finger: $finger_name (Confidence: $actual_confidence)";
		  $access = 1;
	  }
  	}
  }
  
  ##### DOOR OPENER Actions!!! ####
  if($access){
	Log3 "FingerprintDoor", 3, "Öffe Türe - Finger ($finger_name)";
	fhem("set Keymatic open");
  }else{
	if($actual_confidence > $maxConfidence){
		Log3 "FingerprintDoor", 3, "Fehler: Confidence zu hoch ($actual_confidence) - $finger_name ";	
	}else{
		Log3 "FingerprintDoor", 3, "Keine Aktion - Finger ($finger_name) - Tipp: Userreading aktiv oder Hauptschalter aus?";
		}
	}
	# clear reading
	fhem("setreading $NAME finger_id 996");
	
}elsif("$EVENT" =~ m/msg: Unauthorized finger$/){
	# Unbekannten Finger NUR bei geschlossener Türe melden!
	# NUR WENN TÜRE ZU!
	if(ReadingsVal("$NAME", "door", 0) eq "OFF"){
		Log3 "FingerprintDoor", 3, "Unauthorized finger";
	}
	# Restart LED after red blinking
	if(ReadingsVal("dmy_T_W_fingerprint_LED_ready4finger", "state", "off") eq "on"){
		fhem("define at_r4f at +00:00:02 set MQTT2_T_W_fingerprint ready4finger");
	}
	}
}

```




## Device Readings

<img src="doc/fhem.jpg" width="200">

## Setlist 
<img src="doc/fhem2.jpg" width="200">


## Credits
[ESPHome project](https://esphome.io/)

[Helpful ESPHome tutorials](https://www.youtube.com/@Smarthomeyourself)