Note: staff-provided content does not represent an official statement from FARGOS Development, LLC. The policy on staff-authored content can be found here.
Go back to Geoff's home page.
The ultimate result of this project is a door entry system that allows users to scan key fobs to unlock a door. This project adds support for PN5180 NFC tag readers to ESPHome as a local component. Although unrelated, it also adds support for 433 MHz receivers as a second component.
A complete example YAML for using the PN5180 and 433 MHz integrations appears below. Two pre-existing libraries are referenced:
The integration into ESPHome is enabled via external_components. The example below roots these components under the directory path my_components:
external_components:
- source:
type: local
path: my_components
The example makes provision for 6 indicator LEDs:
In practice, a user approaches the tag reader with their key fob and looks for the NFC Tag Detected LED to illuminate. The key fob needs to be held in place until the Tag Read LED is illuminated; it can be removed once the Tag Read LED has indicated a successful read of the NFC tag. The expectation is that the Tag Accepted LED will subsequently be illuminated and the door will be unlocked.
Note that the Tag Accepted LED is turned on under direction of the Home Assistant controlling host to which the ESPHome-based device is connected. The Home Assistant host is also responsible for determination of tag authorization and commanding the door to be unlocked. The Tag Accepted LED will not be illuminated if the Home Assistant host is inoperable or the tag is not in its list of authorized tags.
The YAML below includes an optional on_boot block that flashes the LEDs at startup to prove that they are in working order.
esphome: name: frontdoor-nfc friendly_name: Front Door NFC comment: Decodes Near Field Communication tags project: name: "gcc.fontdoor_nfc" version: "1.2.1" libraries: - pn5180_lib=https://github.com/ATrappmann/PN5180-Library.git#master - SPI on_boot: priority: -100.0 then: - repeat: count: 3 then: - output.turn_on: rf_msg_rcvd_led - delay: 1s - output.turn_off: rf_msg_rcvd_led - delay: 1s - output.turn_on: nfc_detected_indicator - delay: 1s - output.turn_off: nfc_detected_indicator - delay: 1s - output.turn_on: nfc_read_ok_indicator - delay: 1s - output.turn_off: nfc_read_ok_indicator - delay: 1s - switch.turn_on: tag_accepted_indicator - delay: 1s - switch.turn_off: tag_accepted_indicator - delay: 1s - output.turn_on: alive_led - delay: 1s - output.turn_off: alive_led # - delay: 1s # - light.turn_on: statusLED # - delay: 1s # - light.turn_off: statusLED esp32: board: esp32doit-devkit-v1 cpu_frequency: 160MHz framework: type: arduino # esp-idf sdkconfig_options: CONFIG_ESP32_BROWNOUT_DET: "n" CONFIG_ESP_TASK_WDT_TIMEOUT_S: "30" advanced: minimum_chip_revision: "3.1" # sram1_as_iram: true # Enable logging logger: level: debug # very_verbose # Enable Home Assistant API api: encryption: key: "${KEY}" ota: - platform: esphome password: "ESPadmin" wifi: ssid: !secret wifi_ssid password: !secret wifi_password reboot_timeout: 60s power_save_mode: none # since plugged in min_auth_mode: WPA2 # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "FrontDoorNFC" password: "NFCadmin" captive_portal: external_components: - source: type: local path: my_components time: - platform: homeassistant id: system_clock timezone: "America/Chicago" text_sensor: - platform: wifi_info ip_address: name: IP Address id: local_ip_address mac_address: name: WiFi MAC Address id: wifi_mac_address sensor: - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB name: "WiFi Signal dB" id: wifi_signal_db update_interval: 60s entity_category: "diagnostic" - platform: copy # Reports the WiFi signal strength in % id: wifi_signal_strength source_id: wifi_signal_db name: "WiFi Signal Percent" filters: - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0); unit_of_measurement: "Signal %" entity_category: "diagnostic" device_class: "" status_led: id: statusLED pin: GPIO2 switch: - platform: gpio pin: GPIO25 id: tag_accepted_indicator name: "NFC Tag Accepted LED" restore_mode: ALWAYS_OFF on_turn_on: - delay: 5s - switch.turn_off: tag_accepted_indicator output: - platform: gpio pin: GPIO27 id: nfc_detected_indicator - platform: gpio pin: GPIO26 id: nfc_read_ok_indicator # drive_strength: 40mA - platform: gpio pin: GPIO14 id: alive_led - platform: gpio pin: GPIO17 id: rf_msg_rcvd_led # Light component used to blink liveness LED light: - platform: binary name: "Blinking Liveness LED" output: alive_led id: blinking_liveness_led internal: true - platform: binary output: rf_msg_rcvd_led id: blinking_rf_recv_led internal: true on_turn_on: - delay: 2s - light.turn_off: blinking_rf_recv_led # Automation to blink the LED interval: - interval: 1s # Blink every 1 second then: - light.toggle: blinking_liveness_led ask433_receiver: data_pin: GPIO16 msg_data: name: "Message Data" msg_count: name: "Message Count" on_value: then: - light.turn_on: blinking_rf_recv_led spi: id: spi_bus clk_pin: GPIO18 mosi_pin: GPIO23 miso_pin: GPIO19 pn5180: id: nfc_reader spi_id: spi_bus data_rate: 2MHz spi_mode: 3 # Mode 3 (CPOL=1, CPHA=1) # bit_order: msb_first # poll_interval: 500 cs_pin: number: GPIO15 ignore_strapping_warning: false busy_pin: number: GPIO32 reset_pin: number: GPIO33 button1_pin: number: GPIO34 mode: input: true tag_uid: name: "TAG UID" tag_data: name: "TAG DATA" tag_detected: name: "TAG Detected" internal: true on_press: then: - output.turn_on: nfc_detected_indicator on_release: then: - output.turn_off: nfc_detected_indicator tag_read_ok: name: "TAG Read OK" on_press: then: - output.turn_off: nfc_detected_indicator # save power - output.turn_on: nfc_read_ok_indicator on_release: then: - output.turn_off: nfc_read_ok_indicator
The source code for interfacing a PN5180 NFC Tag reader to ESPHome is illustrated below. It is comprised by two files: the __init__.py that exposes the interface to the YAML parser and the C++ pn5180_component.h header that implements the pn5180 component for ESPHome. The YAML presented above specifies a my_components directory path, which would require the two files below to be placed in the config/my_components/pn5180 subdirectory.
Three elements are published to Home Assistant:
import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import spi, text_sensor, binary_sensor, sensor from esphome import pins DEPENDENCIES = ["spi"] AUTO_LOAD = [ "text_sensor", "binary_sensor"] CONF_BUSY_PIN = "busy_pin" CONF_RESET_PIN = "reset_pin" CONF_CS_PIN = "cs_pin" CONF_TAG_UID = "tag_uid" CONF_TAG_DATA = "tag_data" CONF_TAG_DETECTED = "tag_detected" CONF_TAG_READ_OK = "tag_read_ok" CONF_BTN1_PIN = "button1_pin" # CONF_BTN1_STATE = "button1_pressed" pn5180_ns = cg.esphome_ns.namespace("pn5180") PN5180_Device = pn5180_ns.class_( "PN5180_Device", cg.PollingComponent, spi.SPIDevice ) CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(PN5180_Device), cv.Required(CONF_BUSY_PIN): pins.gpio_input_pin_schema, cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_TAG_UID): text_sensor.text_sensor_schema(), cv.Required(CONF_TAG_DATA): text_sensor.text_sensor_schema(), cv.Required(CONF_TAG_DETECTED): binary_sensor.binary_sensor_schema(), cv.Required(CONF_TAG_READ_OK): binary_sensor.binary_sensor_schema(), cv.Optional(CONF_CS_PIN): pins.gpio_output_pin_schema, # cv.Optional(CONF_BTN1_STATE): binary_sensor.binary_sensor_schema(), cv.Optional(CONF_BTN1_PIN): pins.gpio_input_pin_schema, } ) .extend(cv.polling_component_schema("500ms")) .extend(spi.spi_device_schema(cs_pin_required=True)) ) async def to_code(config): var = cg.new_Pvariable(config[cv.CONF_ID]) await cg.register_component(var, config) await spi.register_spi_device(var, config) busy = await cg.gpio_pin_expression(config[CONF_BUSY_PIN]) cg.add(var.set_busy_pin(busy)) reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) cg.add(var.set_reset_pin(reset)) tag = await text_sensor.new_text_sensor(config[CONF_TAG_UID]) cg.add(var.set_tag_uid_sensor(tag)) tag = await text_sensor.new_text_sensor(config[CONF_TAG_DATA]) cg.add(var.set_tag_data_sensor(tag)) sens = await binary_sensor.new_binary_sensor(config[CONF_TAG_DETECTED]) cg.add(var.set_tag_detected_sensor(sens)) sens = await binary_sensor.new_binary_sensor(config[CONF_TAG_READ_OK]) cg.add(var.set_tag_read_ok_sensor(sens)) if CONF_BTN1_PIN in config: pin = await cg.gpio_pin_expression(config[CONF_BTN1_PIN]) cg.add(var.set_button1_pin(pin)) # if CONF_BTN1_STATE in config: # sens = await binary_sensor.new_binary_sensor(config[CONF_BTN1_STATE]) # cg.add(var.set_button1_sensor(sens))
#pragma once #include "esphome/components/spi/spi.h" #include "esphome.h" #include "PN5180.h" #include "PN5180ISO15693.h" using namespace esphome; namespace esphome { namespace pn5180 { static const char hexChars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /*! * \brief Searches for a substring within a buffer. * * \param source is a pointer to the buffer. * \param srcLen indicates the length of the \a source buffer. * \param subString is a pointer to the string to be found. * \param subLen indicates the length of the \a substring. * * \return ~0 is returned if the substring is not found; otherwise the * offset of the first instance on the substring within the \a source * buffer is returned. */ static ssize_t findSubstring(const unsigned char *source, size_t srcLen, const unsigned char *subString, size_t subLen) { /* NOTE: as a practical matter, subLen is not going to be more than 4 gigs, * so we should be able to get away with a mere 32-bit skip list */ enum { MAX_CHARS_IN_A_BYTE = 256 }; uint32_t skip[MAX_CHARS_IN_A_BYTE]; unsigned char c; if ((srcLen == 0) || (subLen == 0)) { // nothing to look at/for return (-1); } if (srcLen < subLen) { // impossible... return (-1); } if (srcLen == subLen) { // either they're equal or not... if (memcmp(source, subString, subLen) == 0) { return (0); } return (-1); } // look for first character using optimized function const unsigned char *ucp = reinterpret_cast<const unsigned char *>(memchr(source, *subString, srcLen)); if (ucp == nullptr) { return (-1); // we'll never find anything } size_t i = ucp - source; // offset if (subLen == 1) { // FAST PATH: single character return (i); } if ((i + subLen) > srcLen) { // too near the end for any match return (-1); // impossible to find match } // FAST PATH: try for a match at very first occurrence if (memcmp(source + i, subString, subLen) == 0) { // found it! return (i); } // Go find it using more complex search // start at end of substring and work backwards towards front // when comparing. // initialize skip table--indicates how many ahead one can skip // when a mismatch occurs // if character doesn't occur within string, the substring can't // contain it, so move right for entire length of substring // Equivalent to: for(i=0;i<MAX_CHARS_IN_A_BYTE;i++) skip[i] = subLen; uint32_t *ulp = skip; for (uint_fast16_t j = 256; j != 0; --j) { // it is impractical to have a substring more than 4 gigabytes long *(ulp++) = static_cast<uint32_t>(subLen); } // memcpy(skip + 2, skip, sizeof(skip) - 2 * sizeof(unsigned long)); const unsigned char *ucp2 = subString; i = subLen - 1; for (size_t j = subLen; j > 0;) { // for each character within the substring j -= 1; c = *(ucp2++); skip[c] = j; } // i = index within source, j = index within substring... for (size_t j = subLen; j > 0;) { j -= 1; c = *(source + i); if (c != *(subString + j)) { // mismatch... const uint32_t skipDistance = skip[c]; const uint32_t charsMatched = (subLen - 1) - j; if (charsMatched > skipDistance) { i += charsMatched + 1; } else { i += skipDistance; } if (i >= srcLen) { return (-1); // past end of source } // restart at end of substring, --j occurs as part // of loop j = subLen; } else { if (j == 0) { break; // all done... } --i; // look at next char... } } return (i); } template <enum spi::SPIBitOrder BIT_ORDER=spi::BIT_ORDER_MSB_FIRST, enum spi::SPIClockPolarity CLOCK_POLARITY=spi::CLOCK_POLARITY_LOW, enum spi::SPIClockPhase CLOCK_PHASE=spi::CLOCK_PHASE_LEADING, enum spi::SPIDataRate DATA_RATE=spi::DATA_RATE_1KHZ> class PN5180_Device_Interface : public PollingComponent, public ::spi::SPIDevice<BIT_ORDER,CLOCK_POLARITY, CLOCK_PHASE, DATA_RATE> { protected: InternalGPIOPin *busy_pin_{nullptr}; InternalGPIOPin *reset_pin_{nullptr}; InternalGPIOPin *button1_pin_{nullptr}; text_sensor::TextSensor *tag_uid_{nullptr}; text_sensor::TextSensor *tag_data_{nullptr}; binary_sensor::BinarySensor *tag_detected_{nullptr}; binary_sensor::BinarySensor *tag_read_ok_{nullptr}; // The PN5180 instance used for reading ISO15693 tags PN5180ISO15693 *pn5180_{nullptr}; public: // set_cs_pin() implememted by SPIDevice() void set_busy_pin(InternalGPIOPin *pin) { busy_pin_ = pin; } void set_reset_pin(InternalGPIOPin *pin) { reset_pin_ = pin; } void set_button1_pin(InternalGPIOPin *pin) { button1_pin_ = pin; } void set_tag_uid_sensor(text_sensor::TextSensor *sensor) { tag_uid_ = sensor; } void set_tag_data_sensor(text_sensor::TextSensor *sensor) { tag_data_ = sensor; } void set_tag_detected_sensor(binary_sensor::BinarySensor *sensor) { tag_detected_ = sensor; } void set_tag_read_ok_sensor(binary_sensor::BinarySensor *sensor) { tag_read_ok_ = sensor; } const char *get_tag_uid() const { return tag_uid_->state.c_str(); } bool tag_uid_has_state() const { return tag_uid_->has_state(); } bool has_state() const { return tag_uid_has_state(); } // Setup function, called once during initialization void setup() override { // Initialize the PN5180 instance uint8_t busy = (busy_pin_ != nullptr) ? busy_pin_->get_pin() : 0; uint8_t reset = (reset_pin_ != nullptr) ? reset_pin_->get_pin() : 0; ESP_LOGI("pn5180", "setup busy=%d reset=%d", busy, reset); uint8_t cs = 0; if (this->cs_ != nullptr) { ESP_LOGI("pn5180", "Doing cast of cs_"); // cs_ is protected member from SPIClient class InternalGPIOPin *csPin = (InternalGPIOPin *)(this->spi::SPIClient::cs_); if (csPin != nullptr) { cs = csPin->get_pin(); ESP_LOGI("pn5180", "Got cs pin=%d", cs); } else { ESP_LOGE("pn5180", "failed to cast cs_pin"); } } //return; ESP_LOGI("pn5180", "creating PN5180ISO15693"); pn5180_ = new PN5180ISO15693(cs, busy, reset); ESP_LOGI("pn5180", "pn5180 begin"); pn5180_->begin(); // Reset and set up the RF settings for the PN5180 ESP_LOGI("pn5180", "pn5180 reset"); pn5180_->reset(); ESP_LOGI("pn5180", "pn5180 setupRF"); pn5180_->setupRF(); ESP_LOGI("pn5180", "pn5180 setup end"); } // end setup // Update function, called periodically according to the update interval void update() override { static enum { IDLE=0, SAW_TAG, READ_DATA, ERROR } read_state = IDLE; uint8_t uid[8]; // Attempt to read the UID of an ISO15693 tag ISO15693ErrorCode rc = pn5180_->getInventory(uid); esp_task_wdt_reset(); // we made forward progress if (rc != ISO15693_EC_OK) { // If reading the UID fails, log an error and update the text sensor to show no tag detected if (read_state != IDLE) { read_state = IDLE; ESP_LOGI("pn5180", "No NFC detected"); tag_uid_->publish_state("NOTAVAIL"); if (tag_detected_ != nullptr) { tag_detected_->publish_state(false); } if (tag_read_ok_ != nullptr) { tag_read_ok_->publish_state(false); } } // end if not in idle state return; } // tag seen if (read_state == READ_DATA) { return; // already published data } read_state = SAW_TAG; if (tag_detected_ != nullptr) { tag_detected_->publish_state(true); } uint8_t blockSize, numBlocks; rc = pn5180_->getSystemInfo(uid, &blockSize, &numBlocks); esp_task_wdt_reset(); // we made forward progress if (rc != ISO15693_EC_OK) { read_state = ERROR; ESP_LOGE("pn5180", "Could not getSystemInfo"); // Reset and set up the RF settings on the PN5180 for the next read if (tag_detected_ != nullptr) { tag_detected_->publish_state(false); } pn5180_->reset(); pn5180_->setupRF(); return; } // Convert the UID to a string; UID received least significant byte first // so we convert it from end to start char asHexString[32]; uint8_t offset = 0; for (int8_t i = sizeof(uid) - 1; i >= 0; i-=1) { uint8_t bits = (uid[i] >> 4) & 0xf; asHexString[offset++] = hexChars[bits]; bits = uid[i] & 0xf; asHexString[offset++] = hexChars[bits]; if (i != 0) { asHexString[offset++] = ':'; } } asHexString[offset] = '\0'; // Print the UID to the log ESP_LOGI("pn5180", "Read blockSize=%d numBlocks=%d UID: %s", blockSize, numBlocks, asHexString); // we're using cards with blockSize=4 and numBlocks=28 enum { MAX_DATA_SIZE = 128 }; // ultimate max would be 8192 with blockSize=32 numBlocks=256 uint8_t cardData[MAX_DATA_SIZE]; uint16_t dataOffset = 0; for(uint8_t blockNum=0; blockNum < numBlocks; blockNum += 1) { rc = pn5180_->readSingleBlock(uid, blockNum, cardData + dataOffset, blockSize); esp_task_wdt_reset(); // we made forward progress if (rc != ISO15693_EC_OK) { ESP_LOGE("pn5180", "Could not readSingleBlock num=%d", blockNum); read_state = ERROR; // Reset and set up the RF settings on the PN5180 for the next read pn5180_->reset(); pn5180_->setupRF(); return; } dataOffset += blockSize; } cardData[dataOffset] = '\0'; ESP_LOGI("pn5180","Data: %s", cardData); uint8_t b_off = 0; char text_bfr[48]; for(uint16_t o1=0; o1 < dataOffset; o1 += 1) { uint8_t bits = (cardData[o1] >> 4) & 0xf; text_bfr[b_off++] = hexChars[bits]; bits = cardData[o1] & 0xf; text_bfr[b_off++] = hexChars[bits]; if (b_off == 32) { text_bfr[b_off] = '\0'; ESP_LOGI("pn5180", "%s", text_bfr); b_off = 0; } } if (b_off != 0) { text_bfr[b_off] = '\0'; ESP_LOGI("pn5180", "%s", text_bfr); } ssize_t startOffset = findSubstring(cardData, dataOffset, (const unsigned char *) "BEGIN:VCARD\n", 12); if (startOffset == -1) { startOffset = 0; } else { startOffset += 12; } ssize_t endOffset = findSubstring(cardData, dataOffset, (const unsigned char *) "END:VCARD", 9); if (endOffset == -1) endOffset = dataOffset; cardData[endOffset] = '\0'; ESP_LOGI("pn5180","Data to pub:\n%s", cardData + startOffset); // Update the text sensor with the UID value read_state = READ_DATA; tag_uid_->publish_state(asHexString); tag_data_->publish_state((const char *) cardData + startOffset); if (tag_read_ok_ != nullptr) { tag_read_ok_->publish_state(true); } // Reset and set up the RF settings on the PN5180 for the next read pn5180_->reset(); pn5180_->setupRF(); } // end update void dump_config() override { #define TAG "pn5180" ESP_LOGCONFIG(TAG, "PN5180 NFC Interface"); ESP_LOGCONFIG(TAG, " Busy Pin = %d", busy_pin_->get_pin()); ESP_LOGCONFIG(TAG, " Reset Pin = %d", reset_pin_->get_pin()); if (button1_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " Button1 Pin = %d", button1_pin_->get_pin()); } else { ESP_LOGCONFIG(TAG, " Button1 Pin NOT SPECIFIED"); } #if 0 this->spi::SPIDevice<BIT_ORDER,CLOCK_POLARITY, CLOCK_PHASE, DATA_RATE>::dump_config(); #endif this->PollingComponent::dump_config(); #undef TAG } // dump_config }; // end class PN5180_Device_Interface<> // use typedef to define default PN5180_Device typedef PN5180_Device_Interface<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1KHZ> PN5180_Device; } // end namespace pn5180 } // end namespace esphome
This sample automation requests a door to be unlocked when one of four possible tag UIDs is seen. It also requests that a Tag Accepted LED be illuminated. Note that one cannot assume that communication is 100% reliable, so burden of turning the LED off is delegated to the remote hardware.
Since the door panel is located outside, it provides a natural location for a 433 MHz receiver board to reside and monitor signals from devices located further out on the property. The Amplitude Shift Keying implementation comes from the RadioHead library.
This is the __init__.py file that describes the ask433_receiver component to ESPHome. The component meta data describes three elements:
import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor, binary_sensor, sensor from esphome import pins AUTO_LOAD = [ "text_sensor", "binary_sensor"] CONF_DATA_PIN = "data_pin" CONF_MSG_DATA = "msg_data" CONF_MSG_COUNT = "msg_count" ask433_ns = cg.esphome_ns.namespace("ASK_433MHz") ASK433_Device = ask433_ns.class_( "ASK_433MHz_Receiver", cg.Component ) CONFIG_SCHEMA = ( cv.Schema( { cv.GenerateID(): cv.declare_id(ASK433_Device), cv.Required(CONF_DATA_PIN): pins.gpio_input_pin_schema, cv.Required(CONF_MSG_DATA): text_sensor.text_sensor_schema(), cv.Optional(CONF_MSG_COUNT): sensor.sensor_schema() } ) # .extend(cv.polling_component_schema("500ms")) ) async def to_code(config): var = cg.new_Pvariable(config[cv.CONF_ID]) await cg.register_component(var, config) pin = await cg.gpio_pin_expression(config[CONF_DATA_PIN]) cg.add(var.set_data_pin(pin)) msg = await text_sensor.new_text_sensor(config[CONF_MSG_DATA]) cg.add(var.set_msg_data_sensor(msg)) if CONF_MSG_COUNT in config: count = await sensor.new_sensor(config[CONF_MSG_COUNT]) cg.add(var.set_msg_counter_sensor(count))
This is the C++ header file that implements the ask433_receiver component for ESPHome.
#pragma once #include "esphome.h" #include "RH_ASK.h" using namespace esphome; namespace esphome { namespace ASK_433MHz { #define TAG "ASK_433MHz_recv" #define UNUSED_PIN 13 class ASK_433MHz_Receiver : public Component { protected: InternalGPIOPin *data_pin_{nullptr}; text_sensor::TextSensor *msg_data_{nullptr}; sensor::Sensor *msg_count_{nullptr}; RH_ASK *radioDevice{nullptr}; uint32_t messagesReceived{0}; public: // set_cs_pin() implememted by SPIDevice() void set_data_pin(InternalGPIOPin *pin) { data_pin_ = pin; } void set_msg_data_sensor(text_sensor::TextSensor *sensor) { msg_data_ = sensor; } void set_msg_counter_sensor(sensor::Sensor *sensor) { msg_count_ = sensor; } const char *get_msg_data() const { return msg_data_->state.c_str(); } bool msg_has_state() const { return msg_data_->has_state(); } bool has_state() const { return msg_has_state(); } // Setup function, called once during initialization void setup() override { ESP_LOGI(TAG, "setup data_pin=%d", data_pin_->get_pin()); // Initialize the radio // data rate, rxPin, txPin, transmitEnablePin radioDevice = new RH_ASK(2000, data_pin_->get_pin(), UNUSED_PIN, UNUSED_PIN); if (radioDevice->init() != 0) { ESP_LOGE(TAG, "Failed to initialize radio on pin %d", data_pin_->get_pin()); return; } ESP_LOGI(TAG, "Initialized radio on pin %d", data_pin_->get_pin()); radioDevice->setModeRx(); } void loop() override { uint8_t bfr[128]; uint8_t bfrLen = sizeof(bfr); bool dataReceived = radioDevice->recv(bfr, &bfrLen); if (dataReceived) { messagesReceived += 1; ESP_LOGI(TAG, "Message: %s", bfr); msg_data_->publish_state((const char *) bfr); msg_count_->publish_state(messagesReceived); } } void dump_config() override { ESP_LOGCONFIG(TAG, "Amplitude Shift Keying 433 MHz Receiver Interface"); ESP_LOGCONFIG(TAG, " Data Pin = %d", data_pin_->get_pin()); if (radioDevice == nullptr) { ESP_LOGCONFIG(TAG, " Radio Device not set"); } else { ESP_LOGCONFIG(TAG, " Radio Device allocated"); } } #undef TAG }; // end class ASK_433MHz_Receiver } // end namespace ASK_433MHz } // end namespace esphome