First of all, I would like to say thank you for the good examples. It has been really helpful.
I'm trying to make an extension to the pn532_i2c component.
Unfortunately this is not something you cover in any of your examples, so I've tried my best to do it myself.
However for some reason I keep getting errors.
But I'm also not quite sure if I'm doing it right.
I've created all the folders and files as you mentioned, but done some modification to the files so that they fit my need.
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import pn532_i2c, sensor
from esphome.const import CONF_ID
DEPENDENCIES = ['pn532_i2c']
CONF_PN532_I2C_ADDR = 0x01
custom_pn532_i2c_component_ns = cg.esphome_ns.namespace('custom_pn532_i2c_component')
CustomPN532I2CComponent = custom_pn532_i2c_component_ns.class_('CustomPN532I2CComponent', pn532_i2c.PN532I2C)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CustomPN532I2CComponent)
}).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/pn532_i2c/pn532_i2c.h"
namespace esphome {
namespace custom_pn532_i2c_component {
class CustomPN532I2CComponent : public pn532_i2c::PN532I2C {
public:
void dump_config() override;
bool write_tag(std::vector<uint8_t> &uid, nfc::NdefMessage *message) {
return this->write_tag_(uid, message);
}
};
} // namespace custom_pn532_i2c_component
} // namespace esphome
#include "esphome/core/log.h"
#include "custom_pn532_i2c_component.h"
namespace esphome {
namespace custom_pn532_i2c_component {
static const char *TAG = "custom_pn532_i2c_component.component";
void CustomPN532I2CComponent::dump_config(){
ESP_LOGCONFIG(TAG, "Custom PN532 I2C component");
}
} // namespace empty_i2c_component
} // namespace esphome
I'm getting no build errors, and I'm also able to install it, but clearly something is wrong.
It feels wrong to both have a 'pn532_i2c' and a 'custom_pn532_i2c_component' component in my ESPHome config (.yaml)
esphome:
name: nfc-tagreader
# Automatically add the mac address to the name
# so you can use a single firmware for all devices
name_add_mac_suffix: 'true'
# If buzzer is enabled, notify on api connection success
on_boot:
priority: -10
then:
- wait_until:
api.connected:
- logger.log: API is connected!
- rtttl.play: "success:d=24,o=5,b=100:c,g,b"
- light.turn_on:
id: led_blue
flash_length: 500ms
- switch.turn_on: buzzer_enabled
- switch.turn_on: led_enabled
esp8266:
board: d1_mini
# Enable logging
logger:
custom_pn532_i2c_component:
id: custom_pn532_board
# Enable Home Assistant API
api:
encryption:
key: "C9DIQNQ07MCb2aUTp70iUx/Sluzn/S3Eple23HrC/u4="
services:
- service: rfidreader_tag_ok
then:
- rtttl.play: "beep:d=16,o=5,b=100:b"
- service: rfidreader_tag_ko
then:
- rtttl.play: "beep:d=8,o=5,b=100:b"
- service: play_rtttl
variables:
song_str: string
then:
- rtttl.play: !lambda 'return song_str;'
- service: write_tag_id
variables:
tag_id: string
then:
- light.turn_on:
id: led_red
brightness: 100%
- lambda: |-
auto message = new nfc::NdefMessage();
std::string uri = "https://www.home-assistant.io/tag/";
uri += tag_id;
message->add_uri_record(uri);
id(custom_pn532_board).write_mode(message);
- rtttl.play: "write:d=24,o=5,b=100:b"
- wait_until:
- lambda: |-
return id(custom_pn532_board).is_writing() == false;
- light.turn_off:
id: led_red
- rtttl.play: "write:d=24,o=5,b=100:b,b"
- service: write_music_tag
variables:
music_url: string
music_info: string
then:
- light.turn_on:
id: led_red
brightness: 100%
- 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(custom_pn532_board).write_mode(message);
- rtttl.play: "write:d=24,o=5,b=100:b"
- wait_until:
- lambda: |-
return id(custom_pn532_board).is_writing() == true;
- light.turn_off:
id: led_red
- rtttl.play: "write:d=24,o=5,b=100:b,b"
ota:
password: "a89fc07420122d2df7e1053f3e7016b5"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Nfc-Tagreader Fallback Hotspot"
password: "uKXj4moHXSZK"
captive_portal:
dashboard_import:
package_import_url: github://LukasMendez/tagreader_homeassistant/tag_reader.yaml
improv_serial:
substitutions:
name: tagreader
friendly_name: TagReader
# 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
# Define buttons for writing tags via HA
button:
- platform: template
name: Paste Tag
id: paste_tag
# Optional variables:
icon: "mdi:content-paste"
on_press:
then:
- light.turn_on:
id: led_blue
brightness: 100%
- lambda: |-
std::vector<uint8_t> newUid = {0xAB, 0x3D, 0xBA, 0x44};
auto message = new nfc::NdefMessage();
ESP_LOGD("tagreader", "Writing new UID: %s", newUid);
// auto my_custom_nfc_component = new CustomNfcToolComponent();
// my_custom_nfc_component.write_tag(newUid, message);
// ((esphome::custom_pn532_i2c_component::CustomPN532I2CComponent *) id(custom_pn532_board))->write_tag(newUid, message);
id(custom_pn532_board)->write_tag(newUid, message);
- rtttl.play: "write:d=24,o=5,b=100:b"
- wait_until:
- lambda: |-
return id(custom_pn532_board).is_writing() == true;
- light.turn_off:
id: led_blue
- rtttl.play: "write:d=24,o=5,b=100:b,b"
- platform: template
name: Write Tag Random
id: write_tag_random
# Optional variables:
icon: "mdi:pencil-box"
on_press:
then:
- light.turn_on:
id: led_red
brightness: 100%
- light.turn_on:
id: led_blue
brightness: 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(custom_pn532_board).write_mode(message);
- rtttl.play: "write:d=24,o=5,b=100:b"
- wait_until:
- lambda: |-
return id(custom_pn532_board).is_writing() == true;
- light.turn_off:
id: led_red
- light.turn_off:
id: led_blue
- rtttl.play: "write:d=24,o=5,b=100:b,b"
- platform: template
name: Clean Tag
id: clean_tag
icon: "mdi:nfc-variant-off"
on_press:
then:
- light.turn_on:
id: led_red
brightness: 100%
- light.turn_on:
id: led_green
brightness: 64.7%
- lambda: 'id(custom_pn532_board).clean_mode();'
- rtttl.play: "write:d=24,o=5,b=100:b"
- wait_until:
- lambda: |-
return id(custom_pn532_board).is_writing() == true;
- light.turn_off:
id: led_red
- light.turn_off:
id: led_green
- rtttl.play: "write:d=24,o=5,b=100:b,b"
- platform: template
name: Cancel writing
id: cancel_writing
icon: "mdi:pencil-off"
on_press:
then:
- lambda: 'id(custom_pn532_board).read_mode();'
- light.turn_off:
id: led_red
- light.turn_off:
id: led_green
- light.turn_off:
id: led_blue
- rtttl.play: "write:d=24,o=5,b=100:b,b"
- platform: restart
name: "${friendly_name} Restart"
entity_category: config
i2c:
scan: False
frequency: 400kHz
globals:
- id: source
type: std::string
- id: url
type: std::string
- id: info
type: std::string
- id: copiedData
type: std::string
restore_value: no # Strings cannot be saved/restored
initial_value: '"No value"'
pn532_i2c:
id: pn532_board
address: 0x01
on_tag:
then:
- if:
condition:
switch.is_on: led_enabled
then:
- light.turn_on:
id: led_green
brightness: 100%
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();
ESP_LOGD("tagreader", "Found payload in record: %s", 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:
- rtttl.play: "success:d=24,o=5,b=100:c,g,b"
# Define the buzzer output
output:
- platform: esp8266_pwm
pin: D0
id: buzzer
- platform: gpio
pin: D8
id: output_red
- platform: gpio
pin: D7
id: output_green
- platform: gpio
pin: D6
id: output_blue
binary_sensor:
- platform: status
name: "${friendly_name} Status"
entity_category: diagnostic
text_sensor:
- platform: version
hide_timestamp: true
name: "${friendly_name} ESPHome Version"
entity_category: diagnostic
- platform: wifi_info
ip_address:
name: "${friendly_name} IP Address"
icon: mdi:wifi
entity_category: diagnostic
ssid:
name: "${friendly_name} Connected SSID"
icon: mdi:wifi-strength-2
entity_category: diagnostic
# Define buzzer as output for RTTTL
rtttl:
output: buzzer
# Configure LED
light:
- platform: binary
internal: true
id: led_red
name: Red
output: output_red
- platform: binary
internal: true
id: led_green
name: Green
output: output_green
restore_mode: RESTORE_DEFAULT_OFF
- platform: binary
internal: true
id: led_blue
name: Blue
output: output_blue
restore_mode: RESTORE_DEFAULT_OFF
The only thing I'm trying to achieve is the possibility to call a protected function which is accessible inside of pn532_i2c.h
so I created a custom component that inherits the class and then exposes a public function that calls the protected member. In theory this should be easy without changing any of the other functionality, but since I'm not experienced in C++ and Python it's not as easy as I wish.
Hope you can help me.