Skip to content

Instantly share code, notes, and snippets.

@Resinchem
Last active November 4, 2023 18:59
Show Gist options
  • Save Resinchem/f832d8e7305730cc0af8932d51f22335 to your computer and use it in GitHub Desktop.
Save Resinchem/f832d8e7305730cc0af8932d51f22335 to your computer and use it in GitHub Desktop.
ESPHome code for a Home Assistant DIY tag reader
# =========================================================
# This code is a slightly modified version of the original
# by Adonno and contains the modifications for some hardware
# changes.
#
# See the following for build details and use:
# YouTube Video: https://youtu.be/5Xo8yc4tQYc
# Written Blog: https://resinchemtech.blogspot.com/2023/07/nfc-tag-reader.html
# =========================================================
esphome:
name: tagreader-basement # <========= Optionally rename
platform: ESP8266
board: d1_mini
on_boot:
priority: -10
then:
- wait_until:
api.connected:
- logger.log: API is connected!
- switch.turn_on: vibra
- light.turn_on:
id: activity_led
brightness: 100%
red: 0%
green: 0%
blue: 100%
flash_length: 500ms
- switch.turn_on: buzzer_enabled
- switch.turn_on: led_enabled
ota:
password: !secret ota_password # <======= CHANGE THIS OR ASSURE YOU HAVE AN OTA PASSWORD IN SECRETS
wifi:
ssid: !secret wifi_ssid # <======= CHANGE THIS OR ASSURE YOU HAVE A WIFI_SSID IN SECRETS
password: !secret wifi_password # <======= CHANGE THIS OR ASSURE YOU HAVE A WIFI PASSWORD IN SECRETS
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Tagreader"
password: !secret ap_password
# Enable Home Assistant API
api:
encryption:
key: "qImmVdjxe45eqioCF6s8AxK200/yyr68tDYva9H/L34=" #your auto-generated key will be different
services:
- service: rfidreader_tag_ok
then:
- switch.turn_on: vibra
- service: rfidreader_tag_ko
then:
- switch.turn_on: vibra
- service: write_tag_id
variables:
tag_id: string
then:
- light.turn_on:
id: activity_led
brightness: 100%
red: 100%
green: 0%
blue: 0%
- lambda: |-
auto message = new nfc::NdefMessage();
std::string uri = "https://www.home-assistant.io/tag/";
uri += tag_id;
message->add_uri_record(uri);
id(pn532_board).write_mode(message);
- switch.turn_on: vibra
- wait_until:
not:
pn532.is_writing:
- light.turn_off:
id: activity_led
- switch.turn_on: vibra
- service: write_music_tag
variables:
music_url: string
music_info: string
then:
- light.turn_on:
id: activity_led
brightness: 100%
red: 100%
green: 0%
blue: 0%
- lambda: |-
auto message = new nfc::NdefMessage();
std::string uri = "";
std::string text = "";
uri += music_url;
text += music_info;
if ( music_url != "" ) {
message->add_uri_record(uri);
}
if ( music_info != "" ) {
message->add_text_record(text);
}
id(pn532_board).write_mode(message);
- switch.turn_on: vibra
- wait_until:
not:
pn532.is_writing:
- light.turn_off:
id: activity_led
- switch.turn_on: vibra
# Enable logging
logger:
substitutions:
name: tagreader_basement # <========= Optionally rename
friendly_name: TagReader Basement # <========= Optionally rename
globals:
- id: source
type: std::string
- id: url
type: std::string
- id: info
type: std::string
captive_portal:
i2c:
scan: False
frequency: 400kHz
# Define switches to control LED and buzzer from HA
switch:
- platform: template
name: "${friendly_name} Buzzer Enabled"
id: buzzer_enabled
icon: mdi:volume-high
optimistic: true
restore_state: true
entity_category: config
- platform: template
name: "${friendly_name} LED enabled"
id: led_enabled
icon: mdi:alarm-light-outline
optimistic: true
restore_state: true
entity_category: config
# Vibration Motor - replaces original piezo buzzer
- platform: gpio
id: vibra
pin: GPIO15
name: "Vibration"
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 500ms
- switch.turn_off: vibra
# Define buttons for writing tags via HA
button:
- platform: template
name: Write Tag Random
id: write_tag_random
# Optional variables:
icon: "mdi:pencil-box"
on_press:
then:
- light.turn_on:
id: activity_led
red: 100%
green: 0%
blue: 100%
- lambda: |-
static const char alphanum[] = "0123456789abcdef";
std::string uri = "https://www.home-assistant.io/tag/";
for (int i = 0; i < 8; i++)
uri += alphanum[random_uint32() % (sizeof(alphanum) - 1)];
uri += "-";
for (int j = 0; j < 3; j++) {
for (int i = 0; i < 4; i++)
uri += alphanum[random_uint32() % (sizeof(alphanum) - 1)];
uri += "-";
}
for (int i = 0; i < 12; i++)
uri += alphanum[random_uint32() % (sizeof(alphanum) - 1)];
auto message = new nfc::NdefMessage();
message->add_uri_record(uri);
ESP_LOGD("tagreader", "Writing payload: %s", uri.c_str());
id(pn532_board).write_mode(message);
- switch.turn_on: vibra
- wait_until:
not:
pn532.is_writing:
- light.turn_off:
id: activity_led
- switch.turn_on: vibra
- platform: template
name: Clean Tag
id: clean_tag
icon: "mdi:nfc-variant-off"
on_press:
then:
- light.turn_on:
id: activity_led
brightness: 100%
red: 100%
green: 100%
blue: 0%
- lambda: 'id(pn532_board).clean_mode();'
- switch.turn_on: vibra
- wait_until:
not:
pn532.is_writing:
- light.turn_off:
id: activity_led
- switch.turn_on: vibra
- platform: template
name: Cancel writing
id: cancel_writing
icon: "mdi:pencil-off"
on_press:
then:
- lambda: 'id(pn532_board).read_mode();'
- light.turn_off:
id: activity_led
- switch.turn_on: vibra
- platform: restart
name: "${friendly_name} Restart"
entity_category: config
pn532_i2c:
id: pn532_board
on_tag:
then:
- if:
condition:
switch.is_on: led_enabled
then:
- light.turn_on:
id: activity_led
brightness: 100%
red: 0%
green: 100%
blue: 0%
flash_length: 500ms
- delay: 0.15s #to fix slow component
- lambda: |-
id(source)="";
id(url)="";
id(info)="";
if (tag.has_ndef_message()) {
auto message = tag.get_ndef_message();
auto records = message->get_records();
for (auto &record : records) {
std::string payload = record->get_payload();
std::string type = record->get_type();
size_t hass = payload.find("https://www.home-assistant.io/tag/");
size_t applemusic = payload.find("https://music.apple.com");
size_t spotify = payload.find("https://open.spotify.com");
size_t sonos = payload.find("sonos-2://");
if (type == "U" and hass != std::string::npos ) {
ESP_LOGD("tagreader", "Found Home Assistant tag NDEF");
id(source)="hass";
id(url)=payload;
id(info)=payload.substr(hass + 34);
}
else if (type == "U" and applemusic != std::string::npos ) {
ESP_LOGD("tagreader", "Found Apple Music tag NDEF");
id(source)="amusic";
id(url)=payload;
}
else if (type == "U" and spotify != std::string::npos ) {
ESP_LOGD("tagreader", "Found Spotify tag NDEF");
id(source)="spotify";
id(url)=payload;
}
else if (type == "U" and sonos != std::string::npos ) {
ESP_LOGD("tagreader", "Found Sonos app tag NDEF");
id(source)="sonos";
id(url)=payload;
}
else if (type == "T" ) {
ESP_LOGD("tagreader", "Found music info tag NDEF");
id(info)=payload;
}
else if ( id(source)=="" ) {
id(source)="uid";
}
}
}
else {
id(source)="uid";
}
- if:
condition:
lambda: 'return ( id(source)=="uid" );'
then:
- homeassistant.tag_scanned: !lambda |-
ESP_LOGD("tagreader", "No HA NDEF, using UID");
return x;
else:
- if:
condition:
lambda: 'return ( id(source)=="hass" );'
then:
- homeassistant.tag_scanned: !lambda 'return id(info);'
else:
- homeassistant.event:
event: esphome.music_tag
data:
reader: !lambda |-
return App.get_name().c_str();
source: !lambda |-
return id(source);
url: !lambda |-
return id(url);
info: !lambda |-
return id(info);
- if:
condition:
switch.is_on: buzzer_enabled
then:
- switch.turn_on: vibra
on_tag_removed:
then:
- homeassistant.event:
event: esphome.tag_removed
# LED Indicator (replaces original WS2812b pixel)
light:
- platform: rgb
id: activity_led
name: "RGB LED"
red: output_red
green: output_green
blue: output_blue
output:
- platform: esp8266_pwm
id: output_red
pin: GPIO2
inverted: true
- platform: esp8266_pwm
id: output_green
pin: GPIO14
inverted: true
- platform: esp8266_pwm
id: output_blue
pin: GPIO12
inverted: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment